/macosx/HBAudio.m

https://github.com/shkolnik/HandBrake · Objective C · 708 lines · 567 code · 104 blank · 37 comment · 103 complexity · 38185d9036eca822662c0e1f263cbab0 MD5 · raw file

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