OSDN Git Service

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