OSDN Git Service

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