5 // Created on 2010-08-30.
9 #import "HBAudioController.h"
12 NSString *keyAudioCodecName = @"keyAudioCodecName";
13 NSString *keyAudioMP4 = @"keyAudioMP4";
14 NSString *keyAudioMKV = @"keyAudioMKV";
15 NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
16 NSString *keyAudioBitrateName = @"keyAudioBitrateName";
17 NSString *keyAudioMinimumBitrate = @"keyAudioMinimumBitrate";
18 NSString *keyAudioMaximumBitrate = @"keyAudioMaximumBitrate";
19 NSString *keyAudioMinimumBitrate6Channel = @"keyAudioMinimumBitrate6Channel";
20 NSString *keyAudioMaximumBitrate6Channel = @"keyAudioMaximumBitrate6Channel";
21 NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
22 NSString *keyAudioMixdownName = @"keyAudioMixdownName";
23 NSString *keyAudioMixdownLimitsToTrackBitRate = @"keyAudioMixdownLimitsToTrackBitRate";
24 NSString *keyAudioMixdownCanBeDefault = @"keyAudioMixdownCanBeDefault";
26 NSString *keyAudioCodec = @"codec";
27 NSString *keyAudioMixdown = @"mixdown";
28 NSString *keyAudioSamplerate = @"samplerate";
29 NSString *keyAudioBitrate = @"bitrate";
31 static NSMutableArray *masterCodecArray = nil;
32 static NSMutableArray *masterSampleRateArray = nil;
33 static NSMutableArray *masterBitRateArray = nil;
34 static NSDictionary *defaultBitRate = nil;
35 static NSDictionary *bitRate384 = nil;
37 @interface NSArray (HBAudioSupport)
38 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
39 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
41 @implementation NSArray (HBAudioSupport)
42 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey reverse: (BOOL) reverse
45 NSDictionary *retval = nil;
46 NSEnumerator *enumerator = reverse ? [self reverseObjectEnumerator] : [self objectEnumerator];
50 while (nil != (dict = [enumerator nextObject]) && nil == retval) {
51 if (nil != (aValue = [dict objectForKey: aKey]) && YES == [aValue isEqual: anObject]) {
57 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
58 { return [self dictionaryWithObject: anObject matchingKey: aKey reverse: NO]; }
59 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
60 { return [self dictionaryWithObject: anObject matchingKey: aKey reverse: YES]; }
64 @implementation HBAudio
67 #pragma mark Object Setup
72 if ([HBAudio class] == self) {
74 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
77 masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked
78 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
79 NSLocalizedString(@"AAC (CoreAudio)", @"AAC (CoreAudio)"), keyAudioCodecName,
80 [NSNumber numberWithInt: HB_ACODEC_CA_AAC], keyAudioCodec,
81 [NSNumber numberWithBool: YES], keyAudioMP4,
82 [NSNumber numberWithBool: YES], keyAudioMKV,
83 [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
84 [NSNumber numberWithInt: 64], keyAudioMinimumBitrate,
85 [NSNumber numberWithInt: 320], keyAudioMaximumBitrate,
86 [NSNumber numberWithInt: 128], keyAudioMinimumBitrate6Channel,
87 [NSNumber numberWithInt: 768], keyAudioMaximumBitrate6Channel,
89 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
90 NSLocalizedString(@"AAC (faac)", @"AAC (faac)"), keyAudioCodecName,
91 [NSNumber numberWithInt: HB_ACODEC_FAAC], keyAudioCodec,
92 [NSNumber numberWithBool: YES], keyAudioMP4,
93 [NSNumber numberWithBool: YES], keyAudioMKV,
94 [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
95 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate,
96 [NSNumber numberWithInt: 320], keyAudioMaximumBitrate,
97 [NSNumber numberWithInt: 192], keyAudioMinimumBitrate6Channel,
98 [NSNumber numberWithInt: 768], keyAudioMaximumBitrate6Channel,
100 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
101 NSLocalizedString(@"MP3 (lame)", @"MP3 (lame)"), keyAudioCodecName,
102 [NSNumber numberWithInt: HB_ACODEC_LAME], keyAudioCodec,
103 [NSNumber numberWithBool: YES], keyAudioMP4,
104 [NSNumber numberWithBool: YES], keyAudioMKV,
105 [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
106 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate,
107 [NSNumber numberWithInt: 320], keyAudioMaximumBitrate,
108 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate6Channel,
109 [NSNumber numberWithInt: 320], keyAudioMaximumBitrate6Channel,
111 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
112 NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName,
113 [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec,
114 [NSNumber numberWithBool: YES], keyAudioMP4,
115 [NSNumber numberWithBool: YES], keyAudioMKV,
116 [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioMustMatchTrack,
117 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate,
118 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate,
119 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate6Channel,
120 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate6Channel,
122 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
123 NSLocalizedString(@"AC3", @"AC3"), keyAudioCodecName,
124 [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec,
125 [NSNumber numberWithBool: YES], keyAudioMP4,
126 [NSNumber numberWithBool: YES], keyAudioMKV,
127 [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
128 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate,
129 [NSNumber numberWithInt: 640], keyAudioMaximumBitrate,
130 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate6Channel,
131 [NSNumber numberWithInt: 640], keyAudioMaximumBitrate6Channel,
133 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
134 NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioCodecName,
135 [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioCodec,
136 [NSNumber numberWithBool: NO], keyAudioMP4,
137 [NSNumber numberWithBool: YES], keyAudioMKV,
138 [NSNumber numberWithInt: HB_ACODEC_DCA], keyAudioMustMatchTrack,
139 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate,
140 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate,
141 [NSNumber numberWithInt: 32], keyAudioMinimumBitrate6Channel,
142 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate6Channel,
144 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
145 NSLocalizedString(@"Vorbis (vorbis)", @"Vorbis (vorbis)"), keyAudioCodecName,
146 [NSNumber numberWithInt: HB_ACODEC_VORBIS], keyAudioCodec,
147 [NSNumber numberWithBool: NO], keyAudioMP4,
148 [NSNumber numberWithBool: YES], keyAudioMKV,
149 [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
150 [NSNumber numberWithInt: 48], keyAudioMinimumBitrate,
151 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate,
152 [NSNumber numberWithInt: 192], keyAudioMinimumBitrate6Channel,
153 [NSNumber numberWithInt: 384], keyAudioMaximumBitrate6Channel,
156 // Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
157 // input sample rate when it finds this 0 value as the selected sample rate. We do this because the input
158 // sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
159 masterSampleRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
160 [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
161 NSLocalizedString(@"Auto", @"Auto"), keyAudioSampleRateName,
162 [NSNumber numberWithInt: 0], keyAudioSamplerate,
164 for (i = 0; i < hb_audio_rates_count; i++) {
165 [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
166 [NSString stringWithUTF8String: hb_audio_rates[i].string], keyAudioSampleRateName,
167 [NSNumber numberWithInt: hb_audio_rates[i].rate], keyAudioSamplerate,
171 masterBitRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
172 int defaultRate = hb_audio_bitrates[hb_audio_bitrates_default].rate;
173 for (i = 0; i < hb_audio_bitrates_count; i++) {
174 int rate = hb_audio_bitrates[i].rate;
175 dict = [NSDictionary dictionaryWithObjectsAndKeys:
176 [NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
177 [NSNumber numberWithInt: rate], keyAudioBitrate,
179 if (rate == defaultRate) {
180 defaultBitRate = [dict retain]; // knowingly leaked
183 bitRate384 = [dict retain]; // knowingly leaked
185 [masterBitRateArray addObject: dict];
193 // Ensure the list of codecs is accurate
194 // Update the current value of codec based on the revised list
195 - (void) updateCodecs
198 NSMutableArray *permittedCodecs = [NSMutableArray array];
199 unsigned int count = [masterCodecArray count];
201 NSString *keyThatAllows = nil;
203 // Determine which key we use to see which codecs are permitted
204 switch ([videoContainerTag intValue]) {
206 keyThatAllows = keyAudioMP4;
209 keyThatAllows = keyAudioMKV;
212 keyThatAllows = @"error condition";
216 // First get a list of the permitted codecs based on the internal rules
217 if (nil != track && YES == [self enabled]) {
220 for (unsigned int i = 0; i < count; i++) {
221 dict = [masterCodecArray objectAtIndex: i];
223 // First make sure only codecs permitted by the container are here
224 goodToAdd = [[dict objectForKey: keyThatAllows] boolValue];
226 // 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
227 if (YES == [[dict objectForKey: keyAudioMustMatchTrack] boolValue]) {
228 if ([[dict objectForKey: keyAudioMustMatchTrack] intValue] != [[[self track] objectForKey: keyAudioInputCodec] intValue]) {
233 if (YES == goodToAdd) {
234 [permittedCodecs addObject: dict];
239 // Now make sure the permitted list and the actual ones matches
240 [self setCodecs: permittedCodecs];
242 // Ensure our codec is on the list of permitted codecs
243 if (nil == [self codec] || NO == [permittedCodecs containsObject: [self codec]]) {
244 if (0 < [permittedCodecs count]) {
245 [self setCodec: [permittedCodecs objectAtIndex: 0]]; // This should be defaulting to Core Audio
248 [self setCodec: nil];
255 // The rules here are provided as-is from the original -[Controller audioTrackPopUpChanged:mixdownToUse:] routine
256 // with the comments taken from there as well.
257 - (void) updateMixdowns
260 NSMutableArray *retval = [NSMutableArray array];
261 int trackCodec = [[track objectForKey: keyAudioInputCodec] intValue];
262 int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
264 if (HB_ACODEC_AC3 == trackCodec && HB_ACODEC_AC3_PASS == codecCodec) {
265 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
266 NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioMixdownName,
267 [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioMixdown,
268 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
269 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
272 else if (HB_ACODEC_DCA == trackCodec && HB_ACODEC_DCA_PASS == codecCodec) {
273 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
274 NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioMixdownName,
275 [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioMixdown,
276 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
277 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
281 int audioCodecsSupport6Ch = (trackCodec && HB_ACODEC_LAME != codecCodec);
282 int channelLayout = [[track objectForKey: keyAudioInputChannelLayout] intValue];
283 int layout = channelLayout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
285 /* add a mono option? */
286 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
287 [NSString stringWithUTF8String: hb_audio_mixdowns[0].human_readable_name], keyAudioMixdownName,
288 [NSNumber numberWithInt: hb_audio_mixdowns[0].amixdown], keyAudioMixdown,
289 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
290 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
293 /* offer stereo if we have a stereo-or-better source */
294 if (layout >= HB_INPUT_CH_LAYOUT_STEREO) {
295 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
296 [NSString stringWithUTF8String: hb_audio_mixdowns[1].human_readable_name], keyAudioMixdownName,
297 [NSNumber numberWithInt: hb_audio_mixdowns[1].amixdown], keyAudioMixdown,
298 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
299 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
303 /* do we want to add a dolby surround (DPL1) option? */
304 if (HB_INPUT_CH_LAYOUT_3F1R == layout || HB_INPUT_CH_LAYOUT_3F2R == layout || HB_INPUT_CH_LAYOUT_DOLBY == layout) {
305 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
306 [NSString stringWithUTF8String: hb_audio_mixdowns[2].human_readable_name], keyAudioMixdownName,
307 [NSNumber numberWithInt: hb_audio_mixdowns[2].amixdown], keyAudioMixdown,
308 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
309 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
313 /* do we want to add a dolby pro logic 2 (DPL2) option? */
314 if (HB_INPUT_CH_LAYOUT_3F2R == layout) {
315 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
316 [NSString stringWithUTF8String: hb_audio_mixdowns[3].human_readable_name], keyAudioMixdownName,
317 [NSNumber numberWithInt: hb_audio_mixdowns[3].amixdown], keyAudioMixdown,
318 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
319 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
323 /* do we want to add a 6-channel discrete option? */
324 if (1 == audioCodecsSupport6Ch && HB_INPUT_CH_LAYOUT_3F2R == layout && (channelLayout & HB_INPUT_CH_LAYOUT_HAS_LFE)) {
325 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
326 [NSString stringWithUTF8String: hb_audio_mixdowns[4].human_readable_name], keyAudioMixdownName,
327 [NSNumber numberWithInt: hb_audio_mixdowns[4].amixdown], keyAudioMixdown,
328 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
329 [NSNumber numberWithBool: (HB_ACODEC_AC3 == trackCodec) ? NO : YES], keyAudioMixdownCanBeDefault,
333 // based on the fact that we are in an else section where the ifs before hand would have detected the following two
334 // situations, the following code will never add anything to the returned array. I am leaving this in place for
335 // historical reasons.
336 /* do we want to add an AC-3 passthrough option? */
337 if (HB_ACODEC_AC3 == trackCodec && HB_ACODEC_AC3_PASS == codecCodec) {
338 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
339 [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name], keyAudioMixdownName,
340 [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioMixdown,
341 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
342 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
346 /* do we want to add a DTS Passthru option ? HB_ACODEC_DCA*/
347 if (HB_ACODEC_DCA == trackCodec && HB_ACODEC_DCA_PASS == codecCodec) {
348 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
349 [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name], keyAudioMixdownName,
350 [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioMixdown,
351 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
352 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
357 // Now make sure the permitted list and the actual ones matches
358 [self setMixdowns: retval];
360 // Ensure our mixdown is on the list of permitted ones
361 if (nil == [self mixdown] || NO == [retval containsObject: [self mixdown]]) {
362 [self setMixdown: [retval lastDictionaryWithObject: [NSNumber numberWithBool: YES] matchingKey: keyAudioMixdownCanBeDefault]];
368 - (void) updateBitRates
371 NSMutableArray *permittedBitRates = [NSMutableArray array];
374 BOOL has6chMixdown = (HB_AMIXDOWN_6CH == [[[self mixdown] objectForKey: keyAudioMixdown] intValue]);
376 count = [masterBitRateArray count];
377 NSString *minKey = (has6chMixdown) ? keyAudioMinimumBitrate6Channel : keyAudioMinimumBitrate;
378 NSString *maxKey = (has6chMixdown) ? keyAudioMaximumBitrate6Channel : keyAudioMaximumBitrate;
379 int minBitRate = [[codec objectForKey: minKey] intValue];
380 int maxBitRate = [[codec objectForKey: maxKey] intValue];
382 int trackInputBitRate = [[[self track] objectForKey: keyAudioInputBitrate] intValue];
383 BOOL limitsToTrackInputBitRate = [[[self mixdown] objectForKey: keyAudioMixdownLimitsToTrackBitRate] boolValue];
386 for (unsigned int i = 0; i < count; i++) {
387 dict = [masterBitRateArray objectAtIndex: i];
388 currentBitRate = [[dict objectForKey: keyAudioBitrate] intValue];
390 // First ensure the bitrate falls within range of the codec
391 shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate);
393 // Now make sure the mixdown is not limiting us to the track input bitrate
394 if (YES == shouldAdd && YES == limitsToTrackInputBitRate) {
395 if (currentBitRate != trackInputBitRate) {
400 // Now make sure the bitrate does not exceed the track's bitrate
401 if (YES == shouldAdd) {
402 if (currentBitRate > trackInputBitRate) {
407 if (YES == shouldAdd) {
408 [permittedBitRates addObject: dict];
412 // There is a situation where we have a mixdown requirement to match the track input bit rate,
413 // but it does not fall into the range the codec supports. Therefore, we force it here.
414 if (YES == limitsToTrackInputBitRate && 0 == [permittedBitRates count]) {
415 NSDictionary *missingBitRate = [masterBitRateArray dictionaryWithObject: [NSNumber numberWithInt: trackInputBitRate] matchingKey: keyAudioBitrate];
416 if (nil == missingBitRate) {
417 // We are in an even worse situation where the requested bit rate does not even exist in the underlying
418 // library of supported bitrates. Of course since this value is ignored we can freely make a bogus one
419 // for the UI just to make the user a little more aware.
420 missingBitRate = [NSDictionary dictionaryWithObjectsAndKeys:
421 [NSString stringWithFormat: @"%d", trackInputBitRate], keyAudioBitrateName,
422 [NSNumber numberWithInt: trackInputBitRate], keyAudioBitrate,
425 [permittedBitRates addObject: missingBitRate];
428 // Make sure we are updated with the permitted list
429 [self setBitRates: permittedBitRates];
431 // Select the proper one
432 if (YES == has6chMixdown) {
433 [self setBitRate: bitRate384];
436 [self setBitRate: defaultBitRate];
438 if (nil == [self bitRate] || NO == [permittedBitRates containsObject: [self bitRate]]) {
439 [self setBitRate: [permittedBitRates lastObject]];
446 #pragma mark Accessors
451 @synthesize sampleRate;
454 @synthesize videoContainerTag;
455 @synthesize controller;
458 @synthesize mixdowns;
459 @synthesize bitRates;
461 - (void) setVideoContainerTag: (NSNumber *) aValue
464 if ((nil != aValue || nil != videoContainerTag) && NO == [aValue isEqual: videoContainerTag]) {
466 [videoContainerTag release];
467 videoContainerTag = aValue;
473 // We do some detection of the None track to do special things.
474 - (void) setTrack: (NSDictionary *) aValue
477 if ((nil != aValue || nil != track) && NO == [aValue isEqual: track]) {
478 BOOL switchingFromNone = [track isEqual: [controller noneTrack]];
479 BOOL switchingToNone = [aValue isEqual: [controller noneTrack]];
487 if (YES == [self enabled]) {
488 [self setSampleRate: [[self sampleRates] objectAtIndex: 0]]; // default to Auto
490 if (YES == switchingFromNone) {
491 [controller switchingTrackFromNone: self];
493 if (YES == switchingToNone) {
494 [controller settingTrackToNone: self];
501 - (void) setCodec: (NSDictionary *) aValue
504 if ((nil != aValue || nil != codec) && NO == [aValue isEqual: codec]) {
508 [self updateMixdowns];
509 [self updateBitRates];
514 - (void) setMixdown: (NSDictionary *) aValue
517 if ((nil != aValue || nil != mixdown) && NO == [aValue isEqual: mixdown]) {
521 [self updateBitRates];
522 [[NSNotificationCenter defaultCenter] postNotificationName: HBMixdownChangedNotification object: self];
527 - (NSArray *) tracks { return [controller masterTrackArray]; }
529 - (NSArray *) sampleRates { return masterSampleRateArray; }
534 [self setTrack: nil];
535 [self setCodec: nil];
536 [self setMixdown: nil];
537 [self setSampleRate: nil];
538 [self setBitRate: nil];
540 [self setVideoContainerTag: nil];
541 [self setCodecs: nil];
542 [self setMixdowns: nil];
543 [self setBitRates: nil];
549 #pragma mark Special Setters
551 - (void) setTrackFromIndex: (int) aValue
554 [self setTrack: [[self tracks] dictionaryWithObject: [NSNumber numberWithInt: aValue] matchingKey: keyAudioTrackIndex]];
558 // This returns whether it is able to set the actual codec desired.
559 - (BOOL) setCodecFromName: (NSString *) aValue
562 NSDictionary *dict = [[self codecs] dictionaryWithObject: aValue matchingKey: keyAudioCodecName];
565 [self setCodec: dict];
567 return (nil != dict);
570 - (void) setMixdownFromName: (NSString *) aValue
573 NSDictionary *dict = [[self mixdowns] dictionaryWithObject: aValue matchingKey: keyAudioMixdownName];
576 [self setMixdown: dict];
581 - (void) setSampleRateFromName: (NSString *) aValue
584 NSDictionary *dict = [[self sampleRates] dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName];
587 [self setSampleRate: dict];
592 - (void) setBitRateFromName: (NSString *) aValue
595 NSDictionary *dict = [[self bitRates] dictionaryWithObject: aValue matchingKey: keyAudioBitrateName];
598 [self setBitRate: dict];
605 #pragma mark Validation
607 // Because we have indicated that the binding for the drc validates immediately we can implement the
608 // key value binding method to ensure the drc stays in our accepted range.
609 - (BOOL) validateDrc: (id *) ioValue error: (NSError *) outError
614 if (nil != *ioValue) {
615 if (0.0 < [*ioValue floatValue] && 1.0 > [*ioValue floatValue]) {
616 *ioValue = [NSNumber numberWithFloat: 1.0];
624 #pragma mark Bindings Support
629 return (nil != track) ? (NO == [track isEqual: [controller noneTrack]]) : NO;
632 - (BOOL) mixdownEnabled
635 BOOL retval = [self enabled];
638 int myMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
639 if (HB_ACODEC_AC3_PASS == myMixdown || HB_ACODEC_DCA_PASS == myMixdown) {
649 BOOL retval = [self enabled];
652 int myTrackCodec = [[[self track] objectForKey: keyAudioInputCodec] intValue];
653 if (HB_ACODEC_AC3 != myTrackCodec) {
660 + (NSSet *) keyPathsForValuesAffectingEnabled
663 return [NSSet setWithObjects: @"track", nil];
666 + (NSSet *) keyPathsForValuesAffectingMixdownEnabled
669 return [NSSet setWithObjects: @"track", @"mixdown", nil];
672 + (NSSet *) keyPathsForValuesAffectingAC3Enabled
675 return [NSSet setWithObjects: @"track", nil];