OSDN Git Service

MacGui: Audio - Using fallback codec no longer sets the bit rate from the preset...
[handbrake-jp/handbrake-jp-git.git] / macosx / HBAudio.m
1 //
2 //  HBAudio.m
3 //  HandBrake
4 //
5 //  Created on 2010-08-30.
6 //
7
8 #import "HBAudio.h"
9 #import "HBAudioController.h"
10 #import "hb.h"
11
12 NSString *keyAudioCodecName = @"keyAudioCodecName";
13 NSString *keyAudioMP4 = @"keyAudioMP4";
14 NSString *keyAudioMKV = @"keyAudioMKV";
15 NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
16 NSString *keyAudioBitrateName = @"keyAudioBitrateName";
17 NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
18 NSString *keyAudioMixdownName = @"keyAudioMixdownName";
19 NSString *keyAudioMixdownLimitsToTrackBitRate = @"keyAudioMixdownLimitsToTrackBitRate";
20 NSString *keyAudioMixdownCanBeDefault = @"keyAudioMixdownCanBeDefault";
21
22 NSString *keyAudioCodec = @"codec";
23 NSString *keyAudioMixdown = @"mixdown";
24 NSString *keyAudioSamplerate = @"samplerate";
25 NSString *keyAudioBitrate = @"bitrate";
26
27 static NSMutableArray *masterCodecArray = nil;
28 static NSMutableArray *masterSampleRateArray = nil;
29 static NSMutableArray *masterBitRateArray = nil;
30
31 @interface NSArray (HBAudioSupport)
32 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
33 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
34 @end
35 @implementation NSArray (HBAudioSupport)
36 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey reverse: (BOOL) reverse
37
38 {
39         NSDictionary *retval = nil;
40         NSEnumerator *enumerator = reverse ? [self reverseObjectEnumerator] : [self objectEnumerator];
41         NSDictionary *dict;
42         id aValue;
43         
44         while (nil != (dict = [enumerator nextObject]) && nil == retval) {
45                 if (nil != (aValue = [dict objectForKey: aKey]) && YES == [aValue isEqual: anObject]) {
46                         retval = dict;
47                 }
48         }
49         return retval;
50 }
51 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
52 {       return [self dictionaryWithObject: anObject matchingKey: aKey reverse: NO];     }
53 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
54 {       return [self dictionaryWithObject: anObject matchingKey: aKey reverse: YES];    }
55
56 @end
57
58 @implementation HBAudio
59
60 #pragma mark -
61 #pragma mark Object Setup
62
63 + (void) load
64
65 {
66         if ([HBAudio class] == self) {
67                 int i;
68                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
69                 NSDictionary *dict;
70                 
71                 masterCodecArray = [[NSMutableArray alloc] init];       //      knowingly leaked
72                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
73                                                                           NSLocalizedString(@"AAC (CoreAudio)", @"AAC (CoreAudio)"), keyAudioCodecName,
74                                                                           [NSNumber numberWithInt: HB_ACODEC_CA_AAC], keyAudioCodec,
75                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
76                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
77                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
78                                                                           nil]];
79                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
80                                                                           NSLocalizedString(@"AAC (faac)", @"AAC (faac)"), keyAudioCodecName,
81                                                                           [NSNumber numberWithInt: HB_ACODEC_FAAC], keyAudioCodec,
82                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
83                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
84                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
85                                                                           nil]];
86                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
87                                                                           NSLocalizedString(@"MP3 (lame)", @"MP3 (lame)"), keyAudioCodecName,
88                                                                           [NSNumber numberWithInt: HB_ACODEC_LAME], keyAudioCodec,
89                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
90                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
91                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
92                                                                           nil]];
93                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
94                                                                           NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName,
95                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec,
96                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
97                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
98                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioMustMatchTrack,
99                                                                           nil]];
100                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
101                                                                           NSLocalizedString(@"AC3", @"AC3"), keyAudioCodecName,
102                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec,
103                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
104                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
105                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
106                                                                           nil]];
107                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
108                                                                           NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioCodecName,
109                                                                           [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioCodec,
110                                                                           [NSNumber numberWithBool: NO], keyAudioMP4,
111                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
112                                                                           [NSNumber numberWithInt: HB_ACODEC_DCA], keyAudioMustMatchTrack,
113                                                                           nil]];
114                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
115                                                                           NSLocalizedString(@"Vorbis (vorbis)", @"Vorbis (vorbis)"), keyAudioCodecName,
116                                                                           [NSNumber numberWithInt: HB_ACODEC_VORBIS], keyAudioCodec,
117                                                                           [NSNumber numberWithBool: NO], keyAudioMP4,
118                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
119                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
120                                                                           nil]];
121                 
122                 //      Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
123                 //      input sample rate when it finds this 0 value as the selected sample rate.  We do this because the input
124                 //      sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
125                 masterSampleRateArray = [[NSMutableArray alloc] init];  //      knowingly leaked
126                 [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
127                                                                                    NSLocalizedString(@"Auto", @"Auto"), keyAudioSampleRateName,
128                                                                                    [NSNumber numberWithInt: 0], keyAudioSamplerate,
129                                                                                    nil]];
130                 for (i = 0; i < hb_audio_rates_count; i++) {
131                         [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
132                                                                                            [NSString stringWithUTF8String: hb_audio_rates[i].string], keyAudioSampleRateName,
133                                                                                            [NSNumber numberWithInt: hb_audio_rates[i].rate], keyAudioSamplerate,
134                                                                                            nil]];
135                 }
136                 
137                 masterBitRateArray = [[NSMutableArray alloc] init];     // knowingly leaked
138                 for (i = 0; i < hb_audio_bitrates_count; i++) {
139                         int rate = hb_audio_bitrates[i].rate;
140                         dict = [NSDictionary dictionaryWithObjectsAndKeys:
141                                         [NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
142                                         [NSNumber numberWithInt: rate], keyAudioBitrate,
143                                         nil];
144                         [masterBitRateArray addObject: dict];
145                 }
146                 
147                 [pool release];
148         }
149         return;
150 }
151
152 //      Ensure the list of codecs is accurate
153 //      Update the current value of codec based on the revised list
154 - (void) updateCodecs
155
156 {
157         NSMutableArray *permittedCodecs = [NSMutableArray array];
158         unsigned int count = [masterCodecArray count];
159         NSDictionary *dict;
160         NSString *keyThatAllows = nil;
161
162         //      Determine which key we use to see which codecs are permitted
163         switch ([videoContainerTag intValue]) {
164                 case HB_MUX_MP4:
165                         keyThatAllows = keyAudioMP4;
166                         break;
167                 case HB_MUX_MKV:
168                         keyThatAllows = keyAudioMKV;
169                         break;
170                 default:
171                         keyThatAllows = @"error condition";
172                         break;
173         }
174
175         //      First get a list of the permitted codecs based on the internal rules
176         if (nil != track && YES == [self enabled]) {
177                 BOOL goodToAdd;
178
179                 for (unsigned int i = 0; i < count; i++) {
180                         dict = [masterCodecArray objectAtIndex: i];
181                         
182                         //      First make sure only codecs permitted by the container are here
183                         goodToAdd = [[dict objectForKey: keyThatAllows] boolValue];
184                         
185                         //      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
186                         if (YES == [[dict objectForKey: keyAudioMustMatchTrack] boolValue]) {
187                                 if ([[dict objectForKey: keyAudioMustMatchTrack] intValue] != [[[self track] objectForKey: keyAudioInputCodec] intValue]) {
188                                         goodToAdd = NO;
189                                 }
190                         }
191                         
192                         if (YES == goodToAdd) {
193                                 [permittedCodecs addObject: dict];
194                         }
195                 }
196         }
197         
198         //      Now make sure the permitted list and the actual ones matches
199         [self setCodecs: permittedCodecs];
200
201         //      Ensure our codec is on the list of permitted codecs
202         if (nil == [self codec] || NO == [permittedCodecs containsObject: [self codec]]) {
203                 if (0 < [permittedCodecs count]) {
204                         [self setCodec: [permittedCodecs objectAtIndex: 0]];    //      This should be defaulting to Core Audio
205                 }
206                 else {
207                         [self setCodec: nil];
208                 }
209         }
210
211         return;
212 }
213
214 //      The rules here are provided as-is from the original -[Controller audioTrackPopUpChanged:mixdownToUse:] routine
215 //      with the comments taken from there as well.
216 - (void) updateMixdowns
217
218 {
219         NSMutableArray *retval = [NSMutableArray array];
220         int trackCodec = [[track objectForKey: keyAudioInputCodec] intValue];
221         int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
222
223         if (HB_ACODEC_AC3 == trackCodec && HB_ACODEC_AC3_PASS == codecCodec) {
224                 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
225                                                         NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioMixdownName,
226                                                         [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioMixdown,
227                                                         [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
228                                                         [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
229                                                         nil]];
230         }
231         else if (HB_ACODEC_DCA == trackCodec && HB_ACODEC_DCA_PASS == codecCodec) {
232                 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
233                                                         NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioMixdownName,
234                                                         [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioMixdown,
235                                                         [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
236                                                         [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
237                                                         nil]];
238         }
239         else {
240                 int audioCodecsSupport6Ch = (trackCodec && HB_ACODEC_LAME != codecCodec);
241                 int channelLayout = [[track objectForKey: keyAudioInputChannelLayout] intValue];
242                 int layout = channelLayout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
243                 
244                 /* add a mono option? */
245                 [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
246                                                         [NSString stringWithUTF8String: hb_audio_mixdowns[0].human_readable_name], keyAudioMixdownName,
247                                                         [NSNumber numberWithInt: hb_audio_mixdowns[0].amixdown], keyAudioMixdown,
248                                                         [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
249                                                         [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
250                                                         nil]];
251                 
252                 /* offer stereo if we have a stereo-or-better source */
253                 if (layout >= HB_INPUT_CH_LAYOUT_STEREO) {
254                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
255                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[1].human_readable_name], keyAudioMixdownName,
256                                                                 [NSNumber numberWithInt: hb_audio_mixdowns[1].amixdown], keyAudioMixdown,
257                                                                 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
258                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
259                                                                 nil]];
260                 }
261         
262                 /* do we want to add a dolby surround (DPL1) option? */
263                 if (HB_INPUT_CH_LAYOUT_3F1R == layout || HB_INPUT_CH_LAYOUT_3F2R == layout || HB_INPUT_CH_LAYOUT_DOLBY == layout) {
264                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
265                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[2].human_readable_name], keyAudioMixdownName,
266                                                                 [NSNumber numberWithInt: hb_audio_mixdowns[2].amixdown], keyAudioMixdown,
267                                                                 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
268                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
269                                                                 nil]];
270                 }
271                 
272                 /* do we want to add a dolby pro logic 2 (DPL2) option? */
273                 if (HB_INPUT_CH_LAYOUT_3F2R == layout) {
274                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
275                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[3].human_readable_name], keyAudioMixdownName,
276                                                                 [NSNumber numberWithInt: hb_audio_mixdowns[3].amixdown], keyAudioMixdown,
277                                                                 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
278                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
279                                                                 nil]];
280                 }
281                 
282                 /* do we want to add a 6-channel discrete option? */
283                 if (1 == audioCodecsSupport6Ch && HB_INPUT_CH_LAYOUT_3F2R == layout && (channelLayout & HB_INPUT_CH_LAYOUT_HAS_LFE)) {
284                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
285                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[4].human_readable_name], keyAudioMixdownName,
286                                                                 [NSNumber numberWithInt: hb_audio_mixdowns[4].amixdown], keyAudioMixdown,
287                                                                 [NSNumber numberWithBool: NO], keyAudioMixdownLimitsToTrackBitRate,
288                                                                 [NSNumber numberWithBool: (HB_ACODEC_AC3 == codecCodec) ? YES : NO], keyAudioMixdownCanBeDefault,
289                                                                 nil]];
290                 }
291                 
292                 //      based on the fact that we are in an else section where the ifs before hand would have detected the following two
293                 //      situations, the following code will never add anything to the returned array.  I am leaving this in place for
294                 //      historical reasons.
295                 /* do we want to add an AC-3 passthrough option? */
296                 if (HB_ACODEC_AC3 == trackCodec && HB_ACODEC_AC3_PASS == codecCodec) {
297                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
298                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name], keyAudioMixdownName,
299                                                                 [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioMixdown,
300                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
301                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
302                                                                 nil]];
303                 }
304                         
305                 /* do we want to add a DTS Passthru option ? HB_ACODEC_DCA*/
306                 if (HB_ACODEC_DCA == trackCodec && HB_ACODEC_DCA_PASS == codecCodec) {
307                         [retval addObject: [NSDictionary dictionaryWithObjectsAndKeys:
308                                                                 [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name], keyAudioMixdownName,
309                                                                 [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioMixdown,
310                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownLimitsToTrackBitRate,
311                                                                 [NSNumber numberWithBool: YES], keyAudioMixdownCanBeDefault,
312                                                                 nil]];
313                 }
314         }
315         
316         //      Now make sure the permitted list and the actual ones matches
317         [self setMixdowns: retval];
318         
319         //      Ensure our mixdown is on the list of permitted ones
320         if (YES == [[NSUserDefaults standardUserDefaults] boolForKey: @"CodecDefaultsMixdown"] ||
321                 nil == [self mixdown] || NO == [retval containsObject: [self mixdown]]) {
322                 [self setMixdown: [retval lastDictionaryWithObject: [NSNumber numberWithBool: YES] matchingKey: keyAudioMixdownCanBeDefault]];
323         }
324         
325         return;
326 }
327
328 - (void) updateBitRates: (BOOL) shouldSetDefault
329
330 {
331         NSMutableArray *permittedBitRates = [NSMutableArray array];
332         int count;
333         NSDictionary *dict;
334         
335         count = [masterBitRateArray count];
336         int minBitRate;
337         int maxBitRate;
338         NSString *defaultBitRate;
339         int currentBitRate;
340         int trackInputBitRate = [[[self track] objectForKey: keyAudioInputBitrate] intValue];
341         BOOL limitsToTrackInputBitRate = [[[self mixdown] objectForKey: keyAudioMixdownLimitsToTrackBitRate] boolValue];
342         BOOL shouldAdd;
343         int theSampleRate = [[[self sampleRate] objectForKey: keyAudioSamplerate] intValue];
344                 
345         if (0 == theSampleRate) {       //      this means Auto
346                 theSampleRate = [[[self track] objectForKey: keyAudioInputSampleRate] intValue];
347                 }
348
349         int ourCodec = [[codec objectForKey: keyAudioCodec] intValue];
350         int ourMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
351         hb_get_audio_bitrate_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
352         int theDefaultBitRate = hb_get_default_audio_bitrate(ourCodec, theSampleRate, ourMixdown);
353         defaultBitRate = [NSString stringWithFormat: @"%d", theDefaultBitRate];
354
355         for (unsigned int i = 0; i < count; i++) {
356                 dict = [masterBitRateArray objectAtIndex: i];
357                 currentBitRate = [[dict objectForKey: keyAudioBitrate] intValue];
358                 
359                 //      First ensure the bitrate falls within range of the codec
360                 shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate);
361                 
362                 //      Now make sure the mixdown is not limiting us to the track input bitrate
363                 if (YES == shouldAdd && YES == limitsToTrackInputBitRate) {
364                         if (currentBitRate != trackInputBitRate) {
365                                 shouldAdd = NO;
366                         }
367                 }
368                                 
369                 if (YES == shouldAdd) {
370                         [permittedBitRates addObject: dict];
371                 }
372         }
373         
374         //      There is a situation where we have a mixdown requirement to match the track input bit rate,
375         //      but it does not fall into the range the codec supports.  Therefore, we force it here.
376         if (YES == limitsToTrackInputBitRate && 0 == [permittedBitRates count]) {
377                 NSDictionary *missingBitRate = [masterBitRateArray dictionaryWithObject: [NSNumber numberWithInt: trackInputBitRate] matchingKey: keyAudioBitrate];
378                 if (nil == missingBitRate) {
379                         //      We are in an even worse situation where the requested bit rate does not even exist in the underlying
380                         //      library of supported bitrates.  Of course since this value is ignored we can freely make a bogus one
381                         //      for the UI just to make the user a little more aware.
382                         missingBitRate = [NSDictionary dictionaryWithObjectsAndKeys:
383                                                           [NSString stringWithFormat: @"%d", trackInputBitRate], keyAudioBitrateName,
384                                                           [NSNumber numberWithInt: trackInputBitRate], keyAudioBitrate,
385                                                           nil];
386                         }
387                 [permittedBitRates addObject: missingBitRate];
388         }
389         
390         //      Make sure we are updated with the permitted list
391         [self setBitRates: permittedBitRates];
392
393         //      Select the proper one
394         if (YES == shouldSetDefault) {
395                 [self setBitRateFromName: defaultBitRate];
396                 }
397
398         if (nil == [self bitRate] || NO == [permittedBitRates containsObject: [self bitRate]]) {
399                 [self setBitRate: [permittedBitRates lastObject]];
400         }
401         
402         return;
403 }
404
405 #pragma mark -
406 #pragma mark Accessors
407
408 @synthesize track;
409 @synthesize codec;
410 @synthesize mixdown;
411 @synthesize sampleRate;
412 @synthesize bitRate;
413 @synthesize drc;
414 @synthesize videoContainerTag;
415 @synthesize controller;
416
417 @synthesize codecs;
418 @synthesize mixdowns;
419 @synthesize bitRates;
420
421 - (void) setVideoContainerTag: (NSNumber *) aValue
422
423 {
424         if ((nil != aValue || nil != videoContainerTag) && NO == [aValue isEqual: videoContainerTag]) {
425                 [aValue retain];
426                 [videoContainerTag release];
427                 videoContainerTag = aValue;
428                 [self updateCodecs];
429         }
430         return;
431 }
432
433 //      We do some detection of the None track to do special things.
434 - (void) setTrack: (NSDictionary *) aValue
435
436 {
437         if ((nil != aValue || nil != track) && NO == [aValue isEqual: track]) {
438                 BOOL switchingFromNone = [track isEqual: [controller noneTrack]];
439                 BOOL switchingToNone = [aValue isEqual: [controller noneTrack]];
440
441                 [aValue retain];
442                 [track release];
443                 track = aValue;
444
445                 if (nil != aValue) {
446                         [self updateCodecs];
447                         if (YES == [self enabled]) {
448                                 [self setSampleRate: [[self sampleRates] objectAtIndex: 0]];    //      default to Auto
449                         }
450                         if (YES == switchingFromNone) {
451                                 [controller switchingTrackFromNone: self];
452                         }
453                         if (YES == switchingToNone) {
454                                 [controller settingTrackToNone: self];
455                         }
456                 }
457         }
458         return;
459 }
460
461 - (void) setCodec: (NSDictionary *) aValue
462
463 {
464         if ((nil != aValue || nil != codec) && NO == [aValue isEqual: codec]) {
465                 [aValue retain];
466                 [codec release];
467                 codec = aValue;
468                 [self updateMixdowns];
469                 [self updateBitRates: YES];
470         }
471         return;
472 }
473
474 - (void) setMixdown: (NSDictionary *) aValue
475
476 {
477         if ((nil != aValue || nil != mixdown) && NO == [aValue isEqual: mixdown]) {
478                 [aValue retain];
479                 [mixdown release];
480                 mixdown = aValue;
481                 [self updateBitRates: YES];
482                 [[NSNotificationCenter defaultCenter] postNotificationName: HBMixdownChangedNotification object: self];
483         }
484         return;
485 }
486
487 - (void) setSampleRate: (NSDictionary *) aValue
488
489 {
490         if ((nil != aValue || nil != sampleRate) && NO == [aValue isEqual: sampleRate]) {
491                 [aValue retain];
492                 [sampleRate release];
493                 sampleRate = aValue;
494                 [self updateBitRates: NO];
495         }
496         return;
497 }
498
499 - (NSArray *) tracks    {       return [controller masterTrackArray];   }
500
501 - (NSArray *) sampleRates       {       return masterSampleRateArray;   }
502
503 - (void) dealloc
504
505 {
506         [self setTrack: nil];
507         [self setCodec: nil];
508         [self setMixdown: nil];
509         [self setSampleRate: nil];
510         [self setBitRate: nil];
511         [self setDrc: nil];
512         [self setVideoContainerTag: nil];
513         [self setCodecs: nil];
514         [self setMixdowns: nil];
515         [self setBitRates: nil];
516         [super dealloc];
517         return;
518 }
519
520 #pragma mark -
521 #pragma mark Special Setters
522
523 - (void) setTrackFromIndex: (int) aValue
524
525 {
526         [self setTrack: [[self tracks] dictionaryWithObject: [NSNumber numberWithInt: aValue] matchingKey: keyAudioTrackIndex]];
527         return;
528 }
529
530 //      This returns whether it is able to set the actual codec desired.
531 - (BOOL) setCodecFromName: (NSString *) aValue
532
533 {
534         NSDictionary *dict = [[self codecs] dictionaryWithObject: aValue matchingKey: keyAudioCodecName];
535         
536         if (nil != dict) {
537                 [self setCodec: dict];
538         }
539         return (nil != dict);
540 }
541
542 - (void) setMixdownFromName: (NSString *) aValue
543
544 {
545         NSDictionary *dict = [[self mixdowns] dictionaryWithObject: aValue matchingKey: keyAudioMixdownName];
546
547         if (nil != dict) {
548                 [self setMixdown: dict];
549         }
550         return;
551 }
552
553 - (void) setSampleRateFromName: (NSString *) aValue
554
555 {
556         NSDictionary *dict = [[self sampleRates] dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName];
557         
558         if (nil != dict) {
559                 [self setSampleRate: dict];
560         }
561         return;
562 }
563
564 - (void) setBitRateFromName: (NSString *) aValue
565
566 {
567         NSDictionary *dict = [[self bitRates] dictionaryWithObject: aValue matchingKey: keyAudioBitrateName];
568         
569         if (nil != dict) {
570                 [self setBitRate: dict];
571         }
572         return;
573 }
574
575
576 #pragma mark -
577 #pragma mark Validation
578
579 //      Because we have indicated that the binding for the drc validates immediately we can implement the
580 //      key value binding method to ensure the drc stays in our accepted range.
581 - (BOOL) validateDrc: (id *) ioValue error: (NSError *) outError
582
583 {
584         BOOL retval = YES;
585         
586         if (nil != *ioValue) {
587                 if (0.0 < [*ioValue floatValue] && 1.0 > [*ioValue floatValue]) {
588                         *ioValue = [NSNumber numberWithFloat: 1.0];
589                 }
590         }
591         
592         return retval;
593 }
594
595 #pragma mark -
596 #pragma mark Bindings Support
597
598 - (BOOL) enabled
599
600 {
601         return (nil != track) ? (NO == [track isEqual: [controller noneTrack]]) : NO;
602 }
603
604 - (BOOL) mixdownEnabled
605
606 {
607         BOOL retval = [self enabled];
608
609         if (YES == retval) {
610                 int myMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
611                 if (HB_ACODEC_AC3_PASS == myMixdown || HB_ACODEC_DCA_PASS == myMixdown) {
612                         retval = NO;
613                 }
614         }
615         return retval;
616 }
617
618 - (BOOL) AC3Enabled
619
620 {
621         BOOL retval = [self enabled];
622         
623         if (YES == retval) {
624                 int myTrackCodec = [[[self track] objectForKey: keyAudioInputCodec] intValue];
625                 if (HB_ACODEC_AC3 != myTrackCodec) {
626                         retval = NO;
627                 }
628         }
629         return retval;
630 }
631
632 + (NSSet *) keyPathsForValuesAffectingEnabled
633
634 {
635         return [NSSet setWithObjects: @"track", nil];
636 }
637
638 + (NSSet *) keyPathsForValuesAffectingMixdownEnabled
639
640 {
641         return [NSSet setWithObjects: @"track", @"mixdown", nil];
642 }
643
644 + (NSSet *) keyPathsForValuesAffectingAC3Enabled
645
646 {
647         return [NSSet setWithObjects: @"track", nil];
648 }
649
650 @end