OSDN Git Service

3be645456881a375fb983a298b421e97c822c99a
[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
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         [self setBitRateFromName: defaultBitRate];
395
396         if (nil == [self bitRate] || NO == [permittedBitRates containsObject: [self bitRate]]) {
397                 [self setBitRate: [permittedBitRates lastObject]];
398         }
399         
400         return;
401 }
402
403 #pragma mark -
404 #pragma mark Accessors
405
406 @synthesize track;
407 @synthesize codec;
408 @synthesize mixdown;
409 @synthesize sampleRate;
410 @synthesize bitRate;
411 @synthesize drc;
412 @synthesize videoContainerTag;
413 @synthesize controller;
414
415 @synthesize codecs;
416 @synthesize mixdowns;
417 @synthesize bitRates;
418
419 - (void) setVideoContainerTag: (NSNumber *) aValue
420
421 {
422         if ((nil != aValue || nil != videoContainerTag) && NO == [aValue isEqual: videoContainerTag]) {
423                 [aValue retain];
424                 [videoContainerTag release];
425                 videoContainerTag = aValue;
426                 [self updateCodecs];
427         }
428         return;
429 }
430
431 //      We do some detection of the None track to do special things.
432 - (void) setTrack: (NSDictionary *) aValue
433
434 {
435         if ((nil != aValue || nil != track) && NO == [aValue isEqual: track]) {
436                 BOOL switchingFromNone = [track isEqual: [controller noneTrack]];
437                 BOOL switchingToNone = [aValue isEqual: [controller noneTrack]];
438
439                 [aValue retain];
440                 [track release];
441                 track = aValue;
442
443                 if (nil != aValue) {
444                         [self updateCodecs];
445                         if (YES == [self enabled]) {
446                                 [self setSampleRate: [[self sampleRates] objectAtIndex: 0]];    //      default to Auto
447                         }
448                         if (YES == switchingFromNone) {
449                                 [controller switchingTrackFromNone: self];
450                         }
451                         if (YES == switchingToNone) {
452                                 [controller settingTrackToNone: self];
453                         }
454                 }
455         }
456         return;
457 }
458
459 - (void) setCodec: (NSDictionary *) aValue
460
461 {
462         if ((nil != aValue || nil != codec) && NO == [aValue isEqual: codec]) {
463                 [aValue retain];
464                 [codec release];
465                 codec = aValue;
466                 [self updateMixdowns];
467                 [self updateBitRates];
468         }
469         return;
470 }
471
472 - (void) setMixdown: (NSDictionary *) aValue
473
474 {
475         if ((nil != aValue || nil != mixdown) && NO == [aValue isEqual: mixdown]) {
476                 [aValue retain];
477                 [mixdown release];
478                 mixdown = aValue;
479                 [self updateBitRates];
480                 [[NSNotificationCenter defaultCenter] postNotificationName: HBMixdownChangedNotification object: self];
481         }
482         return;
483 }
484
485 - (NSArray *) tracks    {       return [controller masterTrackArray];   }
486
487 - (NSArray *) sampleRates       {       return masterSampleRateArray;   }
488
489 - (void) dealloc
490
491 {
492         [self setTrack: nil];
493         [self setCodec: nil];
494         [self setMixdown: nil];
495         [self setSampleRate: nil];
496         [self setBitRate: nil];
497         [self setDrc: nil];
498         [self setVideoContainerTag: nil];
499         [self setCodecs: nil];
500         [self setMixdowns: nil];
501         [self setBitRates: nil];
502         [super dealloc];
503         return;
504 }
505
506 #pragma mark -
507 #pragma mark Special Setters
508
509 - (void) setTrackFromIndex: (int) aValue
510
511 {
512         [self setTrack: [[self tracks] dictionaryWithObject: [NSNumber numberWithInt: aValue] matchingKey: keyAudioTrackIndex]];
513         return;
514 }
515
516 //      This returns whether it is able to set the actual codec desired.
517 - (BOOL) setCodecFromName: (NSString *) aValue
518
519 {
520         NSDictionary *dict = [[self codecs] dictionaryWithObject: aValue matchingKey: keyAudioCodecName];
521         
522         if (nil != dict) {
523                 [self setCodec: dict];
524         }
525         return (nil != dict);
526 }
527
528 - (void) setMixdownFromName: (NSString *) aValue
529
530 {
531         NSDictionary *dict = [[self mixdowns] dictionaryWithObject: aValue matchingKey: keyAudioMixdownName];
532
533         if (nil != dict) {
534                 [self setMixdown: dict];
535         }
536         return;
537 }
538
539 - (void) setSampleRateFromName: (NSString *) aValue
540
541 {
542         NSDictionary *dict = [[self sampleRates] dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName];
543         
544         if (nil != dict) {
545                 [self setSampleRate: dict];
546         }
547         return;
548 }
549
550 - (void) setBitRateFromName: (NSString *) aValue
551
552 {
553         NSDictionary *dict = [[self bitRates] dictionaryWithObject: aValue matchingKey: keyAudioBitrateName];
554         
555         if (nil != dict) {
556                 [self setBitRate: dict];
557         }
558         return;
559 }
560
561
562 #pragma mark -
563 #pragma mark Validation
564
565 //      Because we have indicated that the binding for the drc validates immediately we can implement the
566 //      key value binding method to ensure the drc stays in our accepted range.
567 - (BOOL) validateDrc: (id *) ioValue error: (NSError *) outError
568
569 {
570         BOOL retval = YES;
571         
572         if (nil != *ioValue) {
573                 if (0.0 < [*ioValue floatValue] && 1.0 > [*ioValue floatValue]) {
574                         *ioValue = [NSNumber numberWithFloat: 1.0];
575                 }
576         }
577         
578         return retval;
579 }
580
581 #pragma mark -
582 #pragma mark Bindings Support
583
584 - (BOOL) enabled
585
586 {
587         return (nil != track) ? (NO == [track isEqual: [controller noneTrack]]) : NO;
588 }
589
590 - (BOOL) mixdownEnabled
591
592 {
593         BOOL retval = [self enabled];
594
595         if (YES == retval) {
596                 int myMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
597                 if (HB_ACODEC_AC3_PASS == myMixdown || HB_ACODEC_DCA_PASS == myMixdown) {
598                         retval = NO;
599                 }
600         }
601         return retval;
602 }
603
604 - (BOOL) AC3Enabled
605
606 {
607         BOOL retval = [self enabled];
608         
609         if (YES == retval) {
610                 int myTrackCodec = [[[self track] objectForKey: keyAudioInputCodec] intValue];
611                 if (HB_ACODEC_AC3 != myTrackCodec) {
612                         retval = NO;
613                 }
614         }
615         return retval;
616 }
617
618 + (NSSet *) keyPathsForValuesAffectingEnabled
619
620 {
621         return [NSSet setWithObjects: @"track", nil];
622 }
623
624 + (NSSet *) keyPathsForValuesAffectingMixdownEnabled
625
626 {
627         return [NSSet setWithObjects: @"track", @"mixdown", nil];
628 }
629
630 + (NSSet *) keyPathsForValuesAffectingAC3Enabled
631
632 {
633         return [NSSet setWithObjects: @"track", nil];
634 }
635
636 @end