]> granicus.if.org Git - handbrake/commitdiff
MacGui: rework HBAudioTrack to use less NSDictionary.
authorDamiano Galassi <damiog@gmail.com>
Sat, 3 Sep 2016 16:11:11 +0000 (18:11 +0200)
committerDamiano Galassi <damiog@gmail.com>
Sat, 3 Sep 2016 16:11:11 +0000 (18:11 +0200)
12 files changed:
macosx/English.lproj/Audio.xib
macosx/HBAudio.h
macosx/HBAudio.m
macosx/HBAudioTrack.h
macosx/HBAudioTrack.m
macosx/HBAudioTrackPreset.h
macosx/HBAudioTrackPreset.m
macosx/HBAudioTransformers.h [new file with mode: 0644]
macosx/HBAudioTransformers.m [new file with mode: 0644]
macosx/HBJob+HBJobConversion.m
macosx/HBJob+UIAdditions.m
macosx/HandBrake.xcodeproj/project.pbxproj

index ff7a77e8edac205c8e7a57b759b37c6ef7d24ff9..d24db6cb9ddaf921b9f4c30b2333931da43ceffc 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A238m" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11198.2" systemVersion="16A313a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
     <dependencies>
         <deployment identifier="macosx"/>
-        <development version="7000" identifier="xcode"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11198.2"/>
     </dependencies>
     <objects>
         <customObject id="-2" userLabel="File's Owner" customClass="HBAudioController">
         </customObject>
         <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
         <customObject id="-3" userLabel="Application" customClass="NSObject"/>
-        <arrayController preservesSelection="NO" avoidsEmptySelection="NO" id="rzb-Si-Kpf">
-            <declaredKeys>
-                <string>tracks</string>
-                <string>tracks.keyAudioTrackName</string>
-                <string>track</string>
-                <string>enabled</string>
-                <string>mixdownEnabled</string>
-                <string>drc</string>
-                <string>codecs</string>
-                <string>codecs.keyAudioCodecName</string>
-                <string>codec</string>
-                <string>mixdowns</string>
-                <string>mixdowns.keyAudioMixdownName</string>
-                <string>mixdown</string>
-                <string>sampleRates</string>
-                <string>sampleRates.keyAudioSampleRateName</string>
-                <string>sampleRate</string>
-                <string>bitRates</string>
-                <string>bitRates.keyAudioBitrateName</string>
-                <string>bitRate</string>
-                <string>DRCEnabled</string>
-                <string>gain</string>
-                <string>PassThruEnabled</string>
-                <string>PassThruDisabled</string>
-                <string>bitrateEnabled</string>
-            </declaredKeys>
+        <arrayController objectClassName="HBAudioTrack" preservesSelection="NO" avoidsEmptySelection="NO" id="rzb-Si-Kpf">
             <connections>
                 <binding destination="-2" name="contentArray" keyPath="self.audio.tracks" id="W0u-41-zX4"/>
             </connections>
                                                             <menu key="menu" id="hXU-xc-dxL"/>
                                                         </popUpButtonCell>
                                                         <connections>
-                                                            <binding destination="wJH-tU-zL6" name="content" keyPath="objectValue.masterTrackArray" id="pvQ-pN-TdG"/>
-                                                            <binding destination="wJH-tU-zL6" name="contentValues" keyPath="objectValue.masterTrackArray.keyAudioTrackName" previousBinding="pvQ-pN-TdG" id="Wec-Fo-DSj"/>
-                                                            <binding destination="wJH-tU-zL6" name="selectedObject" keyPath="objectValue.track" previousBinding="Wec-Fo-DSj" id="Qoy-ym-QWQ"/>
+                                                            <binding destination="wJH-tU-zL6" name="selectedIndex" keyPath="objectValue.sourceTrackIdx" previousBinding="LnY-7P-b37" id="CWi-rR-r7Y"/>
+                                                            <binding destination="wJH-tU-zL6" name="content" keyPath="objectValue.sourceTracksArray" id="LnY-7P-b37"/>
                                                         </connections>
                                                     </popUpButton>
                                                 </subviews>
                                                             </connections>
                                                         </popUpButtonCell>
                                                         <connections>
-                                                            <binding destination="8ed-5g-y6e" name="selectedObject" keyPath="objectValue.codec" previousBinding="cvm-Mj-Drh" id="sEl-p7-19g"/>
-                                                            <binding destination="8ed-5g-y6e" name="content" keyPath="objectValue.codecs" id="pxN-GH-Dfr"/>
-                                                            <binding destination="8ed-5g-y6e" name="contentValues" keyPath="objectValue.codecs.keyAudioCodecName" previousBinding="pxN-GH-Dfr" id="cvm-Mj-Drh"/>
-                                                            <binding destination="8ed-5g-y6e" name="enabled" keyPath="objectValue.enabled" id="V0U-a3-ZBW"/>
+                                                            <binding destination="8ed-5g-y6e" name="selectedValue" keyPath="objectValue.encoder" previousBinding="Ojx-pY-iTj" id="aRL-2h-rz1">
+                                                                <dictionary key="options">
+                                                                    <string key="NSValueTransformerName">HBEncoderTransformer</string>
+                                                                </dictionary>
+                                                            </binding>
+                                                            <binding destination="8ed-5g-y6e" name="content" keyPath="objectValue.encoders" id="Ojx-pY-iTj"/>
+                                                            <binding destination="8ed-5g-y6e" name="enabled" keyPath="objectValue.isEnabled" id="hNs-V2-g3t"/>
                                                         </connections>
                                                     </popUpButton>
                                                 </subviews>
                                                             <menu key="menu" id="5Ha-Of-SJF"/>
                                                         </popUpButtonCell>
                                                         <connections>
-                                                            <binding destination="JWs-Gl-4kd" name="selectedObject" keyPath="objectValue.mixdown" previousBinding="mrr-Rw-0Km" id="fAC-AG-TmT"/>
-                                                            <binding destination="JWs-Gl-4kd" name="enabled" keyPath="objectValue.mixdownEnabled" id="anJ-dk-glQ"/>
+                                                            <binding destination="JWs-Gl-4kd" name="enabled" keyPath="objectValue.isEnabled" id="tgd-cw-Xvj"/>
+                                                            <binding destination="JWs-Gl-4kd" name="selectedValue" keyPath="objectValue.mixdown" previousBinding="N2w-i8-sMD" id="0hr-bn-M8A">
+                                                                <dictionary key="options">
+                                                                    <string key="NSValueTransformerName">HBMixdownTransformer</string>
+                                                                </dictionary>
+                                                            </binding>
+                                                            <binding destination="JWs-Gl-4kd" name="enabled2" keyPath="objectValue.mixdownEnabled" previousBinding="tgd-cw-Xvj" id="cYM-fO-KQf">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
                                                             <binding destination="JWs-Gl-4kd" name="content" keyPath="objectValue.mixdowns" id="N2w-i8-sMD"/>
-                                                            <binding destination="JWs-Gl-4kd" name="contentValues" keyPath="objectValue.mixdowns.keyAudioMixdownName" previousBinding="N2w-i8-sMD" id="mrr-Rw-0Km"/>
                                                         </connections>
                                                     </popUpButton>
                                                 </subviews>
                                                             <menu key="menu" id="phf-E4-JNn"/>
                                                         </popUpButtonCell>
                                                         <connections>
-                                                            <binding destination="iQl-Lr-pqe" name="enabled" keyPath="objectValue.mixdownEnabled" id="7np-q0-yTV"/>
-                                                            <binding destination="iQl-Lr-pqe" name="selectedObject" keyPath="objectValue.sampleRate" previousBinding="lhu-ag-YDS" id="2BU-o2-PJ0"/>
+                                                            <binding destination="iQl-Lr-pqe" name="enabled" keyPath="objectValue.isEnabled" id="XCQ-bF-dAC"/>
+                                                            <binding destination="iQl-Lr-pqe" name="enabled2" keyPath="objectValue.mixdownEnabled" previousBinding="XCQ-bF-dAC" id="apI-pR-y7v">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
+                                                            <binding destination="iQl-Lr-pqe" name="selectedValue" keyPath="objectValue.sampleRate" previousBinding="Q5x-J9-u3J" id="hlm-8l-ATk">
+                                                                <dictionary key="options">
+                                                                    <string key="NSNullPlaceholder">Auto</string>
+                                                                    <string key="NSValueTransformerName">HBSampleRateTransformer</string>
+                                                                </dictionary>
+                                                            </binding>
                                                             <binding destination="iQl-Lr-pqe" name="content" keyPath="objectValue.sampleRates" id="Q5x-J9-u3J"/>
-                                                            <binding destination="iQl-Lr-pqe" name="contentValues" keyPath="objectValue.sampleRates.keyAudioSampleRateName" previousBinding="Q5x-J9-u3J" id="lhu-ag-YDS"/>
                                                         </connections>
                                                     </popUpButton>
                                                 </subviews>
                                                             <menu key="menu" id="DFY-hE-Hi6"/>
                                                         </popUpButtonCell>
                                                         <connections>
-                                                            <binding destination="Acc-Cw-PLD" name="selectedObject" keyPath="objectValue.bitRate" previousBinding="cgA-Y3-ucA" id="9OJ-Wp-j0I"/>
+                                                            <binding destination="Acc-Cw-PLD" name="selectedValue" keyPath="objectValue.bitRate" previousBinding="S0T-S3-WF5" id="y8e-kU-Kay">
+                                                                <dictionary key="options">
+                                                                    <string key="NSValueTransformerName">HBIntegerTransformer</string>
+                                                                </dictionary>
+                                                            </binding>
                                                             <binding destination="Acc-Cw-PLD" name="content" keyPath="objectValue.bitRates" id="S0T-S3-WF5"/>
-                                                            <binding destination="Acc-Cw-PLD" name="contentValues" keyPath="objectValue.bitRates.keyAudioBitrateName" previousBinding="S0T-S3-WF5" id="cgA-Y3-ucA"/>
-                                                            <binding destination="Acc-Cw-PLD" name="enabled" keyPath="objectValue.bitrateEnabled" id="woZ-ZV-ZQJ"/>
+                                                            <binding destination="Acc-Cw-PLD" name="enabled2" keyPath="objectValue.bitrateEnabled" previousBinding="vzn-iK-rgP" id="7aV-gO-WvY">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
+                                                            <binding destination="Acc-Cw-PLD" name="enabled" keyPath="objectValue.isEnabled" id="vzn-iK-rgP"/>
                                                         </connections>
                                                     </popUpButton>
                                                 </subviews>
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                         </textFieldCell>
                                                         <connections>
-                                                            <binding destination="wfV-Pi-jHd" name="enabled" keyPath="objectValue.PassThruDisabled" id="NnK-Vf-hM6"/>
                                                             <binding destination="wfV-Pi-jHd" name="value" keyPath="objectValue.gain" id="7hD-ql-cNT">
                                                                 <dictionary key="options">
                                                                     <bool key="NSValidatesImmediately" value="YES"/>
                                                                 </dictionary>
                                                             </binding>
+                                                            <binding destination="wfV-Pi-jHd" name="enabled" keyPath="objectValue.isEnabled" id="OrM-Yv-Fs0"/>
+                                                            <binding destination="wfV-Pi-jHd" name="enabled2" keyPath="objectValue.passThruDisabled" previousBinding="OrM-Yv-Fs0" id="d6m-q5-unj">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
                                                         </connections>
                                                     </textField>
                                                     <slider horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gtC-MM-esd">
                                                         <rect key="frame" x="3" y="2" width="22" height="22"/>
                                                         <sliderCell key="cell" controlSize="small" continuous="YES" alignment="left" minValue="-5" maxValue="16" doubleValue="0.25" numberOfTickMarks="21" allowsTickMarkValuesOnly="YES" sliderType="circular" id="BBQ-FP-aQN"/>
                                                         <connections>
-                                                            <binding destination="wfV-Pi-jHd" name="enabled" keyPath="objectValue.PassThruDisabled" id="Wz3-ZW-SLi"/>
                                                             <binding destination="wfV-Pi-jHd" name="value" keyPath="objectValue.gain" id="bKN-kD-NjJ">
                                                                 <dictionary key="options">
                                                                     <bool key="NSValidatesImmediately" value="YES"/>
                                                                 </dictionary>
                                                             </binding>
+                                                            <binding destination="wfV-Pi-jHd" name="enabled" keyPath="objectValue.isEnabled" id="7nL-Mg-i86"/>
+                                                            <binding destination="wfV-Pi-jHd" name="enabled2" keyPath="objectValue.passThruDisabled" previousBinding="7nL-Mg-i86" id="y1g-gJ-0g6">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
                                                         </connections>
                                                     </slider>
                                                 </subviews>
                                                         <rect key="frame" x="3" y="1" width="22" height="22"/>
                                                         <sliderCell key="cell" controlSize="small" continuous="YES" alignment="left" maxValue="4" numberOfTickMarks="16" allowsTickMarkValuesOnly="YES" sliderType="circular" id="nII-CW-aWc"/>
                                                         <connections>
-                                                            <binding destination="RMf-U7-5Td" name="enabled" keyPath="objectValue.DRCEnabled" id="tzk-tB-jEf"/>
+                                                            <binding destination="RMf-U7-5Td" name="enabled2" keyPath="objectValue.drcEnabled" previousBinding="UGi-Kk-MwK" id="dVM-pa-gKf">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
                                                             <binding destination="RMf-U7-5Td" name="value" keyPath="objectValue.drc" id="GxO-He-2yi">
                                                                 <dictionary key="options">
                                                                     <bool key="NSValidatesImmediately" value="YES"/>
                                                                 </dictionary>
                                                             </binding>
+                                                            <binding destination="RMf-U7-5Td" name="enabled" keyPath="objectValue.isEnabled" id="UGi-Kk-MwK"/>
                                                         </connections>
                                                     </slider>
                                                     <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yPh-4R-HRQ">
                                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                                         </textFieldCell>
                                                         <connections>
-                                                            <binding destination="RMf-U7-5Td" name="enabled" keyPath="objectValue.DRCEnabled" id="FS6-ca-Kmi"/>
+                                                            <binding destination="RMf-U7-5Td" name="enabled2" keyPath="objectValue.drcEnabled" previousBinding="Vv3-g9-exh" id="lY2-Z2-4bl">
+                                                                <dictionary key="options">
+                                                                    <integer key="NSMultipleValuesPlaceholder" value="-1"/>
+                                                                    <integer key="NSNoSelectionPlaceholder" value="-1"/>
+                                                                    <integer key="NSNotApplicablePlaceholder" value="-1"/>
+                                                                    <integer key="NSNullPlaceholder" value="-1"/>
+                                                                </dictionary>
+                                                            </binding>
                                                             <binding destination="RMf-U7-5Td" name="value" keyPath="objectValue.drc" id="f0P-bz-w9a">
                                                                 <dictionary key="options">
                                                                     <bool key="NSValidatesImmediately" value="YES"/>
                                                                 </dictionary>
                                                             </binding>
+                                                            <binding destination="RMf-U7-5Td" name="enabled" keyPath="objectValue.isEnabled" id="Vv3-g9-exh"/>
                                                         </connections>
                                                     </textField>
                                                 </subviews>
                 <constraint firstAttribute="bottom" secondItem="Yzu-Rk-hTv" secondAttribute="bottom" constant="20" symbolic="YES" id="uil-Nm-DIV"/>
                 <constraint firstItem="jrP-M5-2Rq" firstAttribute="baseline" secondItem="vFP-nq-IQg" secondAttribute="baseline" id="y3i-kl-lge"/>
             </constraints>
-            <point key="canvasLocation" x="730" y="-14"/>
+            <point key="canvasLocation" x="557" y="-38"/>
         </view>
         <menu id="hyy-qd-qpe">
             <items>
index 045970e6afb72335d3bb0cbbfbbbdcfa5f3a2c0e..d56f59d16fd2d5b1cd98b23876c878d09d7ec6e6 100644 (file)
@@ -19,7 +19,9 @@ extern NSString *HBAudioChangedNotification;
 
 - (instancetype)initWithTitle:(HBTitle *)title;
 
-@property (nonatomic, readonly) NSMutableArray *tracks;
+@property (nonatomic, readonly) NSMutableArray<NSDictionary *> *sourceTracks;
+@property (nonatomic, readonly) NSMutableArray<HBAudioTrack *> *tracks;
+
 @property (nonatomic, readwrite) HBAudioDefaults *defaults;
 
 - (void)addAllTracks;
@@ -27,8 +29,6 @@ extern NSString *HBAudioChangedNotification;
 - (void)reloadDefaults;
 
 - (BOOL)anyCodecMatches:(int)codec;
-- (void)settingTrackToNone:(HBAudioTrack *)newNoneTrack;
-- (void)switchingTrackFromNone:(nullable HBAudioTrack *)noLongerNoneTrack;
 
 @property (nonatomic, readwrite) int container;
 @property (nonatomic, readwrite, weak, nullable) NSUndoManager *undo;
index 8f8872777cb0f592b34de5357c0d23cfa1e07f28..81936d790704203ed021571f3f77af389ba24f7e 100644 (file)
 
 #include "hb.h"
 
+#define NONE_TRACK_INDEX 0
+
 NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
 
 @interface HBAudio () <HBAudioTrackDataSource, HBAudioTrackDelegate>
-
-@property (nonatomic, readonly, strong) NSDictionary *noneTrack;
-@property (nonatomic, readonly, strong) NSArray *masterTrackArray;  // the master list of audio tracks from the title
-
 @end
 
 @implementation HBAudio
@@ -33,192 +31,172 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
     {
         _container = HB_MUX_MP4;
 
+        _sourceTracks = [title.audioTracks mutableCopy];
         _tracks = [[NSMutableArray alloc] init];
         _defaults = [[HBAudioDefaults alloc] init];
 
-        _noneTrack = @{keyAudioTrackIndex: @0,
-                        keyAudioTrackName: NSLocalizedString(@"None", @"None"),
-                        keyAudioInputCodec: @0};
-
-        NSMutableArray *sourceTracks = [NSMutableArray array];
-        [sourceTracks addObject:_noneTrack];
-        [sourceTracks addObjectsFromArray:title.audioTracks];
-        _masterTrackArray = [sourceTracks copy];
-
-        [self switchingTrackFromNone: nil]; // this ensures there is a None track at the end of the list
+        // Add the none and foreign track to the source array
+        NSDictionary *none = @{keyAudioTrackName: NSLocalizedString(@"None", nil)};
+        [_sourceTracks insertObject:none atIndex:0];
     }
     return self;
 }
 
-- (void)addAllTracks
+#pragma mark - Data Source
+
+- (NSDictionary<NSString *, id> *)sourceTrackAtIndex:(NSUInteger)idx;
 {
-    [self addTracksFromDefaults:YES];
+    return self.sourceTracks[idx];
 }
 
-- (void)removeAll
+- (NSArray<NSString *> *)sourceTracksArray
 {
-    [self _clearAudioArray];
-    [self switchingTrackFromNone:nil];
+    NSMutableArray *sourceNames = [NSMutableArray array];
+
+    for (NSDictionary *track in self.sourceTracks)
+    {
+        [sourceNames addObject:track[keyAudioTrackName]];
+    }
+
+    return sourceNames;
 }
 
-- (void)reloadDefaults
+#pragma mark - Delegate
+
+- (void)track:(HBAudioTrack *)track didChangeSourceFrom:(NSUInteger)oldSourceIdx;
 {
-    [self addTracksFromDefaults:NO];
+    // If the source was changed to None, remove the track
+    if (track.sourceTrackIdx == NONE_TRACK_INDEX)
+    {
+        NSUInteger idx = [self.tracks indexOfObject:track];
+        [self removeObjectFromTracksAtIndex:idx];
+    }
+    // Else add a new None track
+    else if (oldSourceIdx == NONE_TRACK_INDEX)
+    {
+        [self addNoneTrack];
+    }
 }
 
-- (void)_clearAudioArray
+- (void)addNoneTrack
+{
+    HBAudioTrack *track = [self trackFromSourceTrackIndex:NONE_TRACK_INDEX];
+    [self addTrack:track];
+}
+
+#pragma mark - Public methods
+
+- (void)addAllTracks
 {
-    while (0 < [self countOfTracks])
+    while (self.countOfTracks)
     {
-        [self removeObjectFromTracksAtIndex: 0];
+        [self removeObjectFromTracksAtIndex:0];
+    }
+
+    // Add the remainings tracks
+    for (NSUInteger idx = 1; idx < self.sourceTracksArray.count; idx++) {
+        [self addTrack:[self trackFromSourceTrackIndex:idx]];
     }
+
+    [self addNoneTrack];
 }
 
-/**
- *  Uses the templateAudioArray from the preset to create the audios for the specified trackIndex.
- *
- *  @param templateAudioArray the track template.
- *  @param trackIndex         the index of the source track.
- *  @param firstOnly          use only the first track of the template or all.
- */
-- (void)_processPresetAudioArray:(NSArray *)templateAudioArray forTrack:(NSUInteger)trackIndex firstOnly:(BOOL)firstOnly
+- (void)removeAll
 {
-    for (HBAudioTrackPreset *preset in templateAudioArray)
+    while (self.countOfTracks)
     {
-        BOOL fallenBack = NO;
-        HBAudioTrack *newAudio = [[HBAudioTrack alloc] init];
-        [newAudio setDataSource:self];
-        [newAudio setDelegate:self];
-        [self insertObject: newAudio inTracksAtIndex: [self countOfTracks]];
-        [newAudio setContainer:self.container];
-        [newAudio setTrackFromIndex: (int)trackIndex];
-        [newAudio setUndo:self.undo];
+        [self removeObjectFromTracksAtIndex:0];
+    }
+    [self addNoneTrack];
+}
 
-        const char *name = hb_audio_encoder_get_name(preset.encoder);
-        NSString *audioEncoder = nil;
+- (void)reloadDefaults
+{
+    [self addTracksFromDefaults];
+}
 
-        // Check if we need to use a fallback
-        if (name)
+- (void)setContainer:(int)container
+{
+    _container = container;
+    if (!(self.undo.isUndoing || self.undo.isRedoing))
+    {
+        for (HBAudioTrack *track in self.tracks)
         {
-            audioEncoder = @(name);
-            if (preset.encoder & HB_ACODEC_PASS_FLAG &&
-                ![newAudio setCodecFromName:audioEncoder])
-            {
-                int passthru, fallback;
-                fallenBack = YES;
-                passthru   = hb_audio_encoder_get_from_name([audioEncoder UTF8String]);
-                fallback   = hb_audio_encoder_get_fallback_for_passthru(passthru);
-                name       = hb_audio_encoder_get_name(fallback);
-
-                // If we couldn't find an encoder for the passthru format
-                // fall back to the selected encoder fallback
-                if (name == NULL)
-                {
-                    name = hb_audio_encoder_get_name(self.defaults.encoderFallback);
-                }
-            }
-            else
-            {
-                name = hb_audio_encoder_sanitize_name([audioEncoder UTF8String]);
-            }
-            audioEncoder = @(name);
+            track.container = container;
         }
 
-        // If our preset wants us to support a codec that the track does not support, instead
-        // of changing the codec we remove the audio instead.
-        if ([newAudio setCodecFromName:audioEncoder])
-        {
-            const char *mixdown = hb_mixdown_get_name(preset.mixdown);
-            if (mixdown)
-            {
-                [newAudio setMixdownFromName: @(mixdown)];
-            }
+        // Update the Auto Passthru Fallback Codec Popup
+        // lets get the tag of the currently selected item first so we might reset it later
+        [self.defaults validateEncoderFallbackForVideoContainer:container];
 
-            const char *sampleRateName = hb_audio_samplerate_get_name(preset.sampleRate);
-            if (!sampleRateName)
-            {
-                [newAudio setSampleRateFromName: @"Auto"];
-            }
-            else
-            {
-                [newAudio setSampleRateFromName: @(sampleRateName)];
-            }
-            if (!fallenBack)
-            {
-                [newAudio setBitRateFromName: [NSString stringWithFormat:@"%d", preset.bitRate]];
-            }
-            [newAudio setDrc:preset.drc];
-            [newAudio setGain:preset.gain];
-        }
-        else
-        {
-            [self removeObjectFromTracksAtIndex: [self countOfTracks] - 1];
-        }
+        //[self validatePassthru];
+    }
+}
 
-        if (firstOnly)
-        {
-            break;
-        }
+- (void)setUndo:(NSUndoManager *)undo
+{
+    _undo = undo;
+    for (HBAudioTrack *track in self.tracks)
+    {
+        track.undo = undo;
+    }
+    self.defaults.undo = undo;
+}
+
+- (void)setDefaults:(HBAudioDefaults *)defaults
+{
+    if (defaults != _defaults)
+    {
+        [[self.undo prepareWithInvocationTarget:self] setDefaults:_defaults];
     }
+    _defaults = defaults;
+    _defaults.undo = self.undo;
 }
 
 /**
- *  Matches the source audio tracks with the specific language iso code.
+ *  Convenience method to add a track to tracks array.
  *
- *  @param isoCode         the iso code to match.
- *  @param selectOnlyFirst whether to match only the first track for the iso code.
- *
- *  @return a NSIndexSet with the index of the matched tracks.
+ *  @param track the track to add.
  */
-- (NSIndexSet *)_tracksWithISOCode:(NSString *)isoCode selectOnlyFirst:(BOOL)selectOnlyFirst
+- (void)addTrack:(HBAudioTrack *)newTrack
 {
-    NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
-
-    // We search for the prefix noting that our titles have the format %d: %s where the %s is the prefix
-    [self.masterTrackArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
-        if (idx) // Note that we skip the "None" track
-        {
-            if ([isoCode isEqualToString:@"und"] ||  [obj[keyAudioTrackLanguageIsoCode] isEqualToString:isoCode])
-            {
-                [indexes addIndex:idx];
-
-                if (selectOnlyFirst)
-                {
-                    *stop = YES;
-                }
-            }
-        }
-    }];
-
-    return indexes;
+    [self insertObject:newTrack inTracksAtIndex:[self countOfTracks]];
 }
 
-- (void)_processPresetAudioArray:(NSArray *)templateAudioArray forTracks:(NSIndexSet *)trackIndexes firstOnly:(BOOL)firstOnly
+/**
+ *  Creates a new track dictionary from a source track.
+ *
+ *  @param index the index of the source track in the sourceTracks array
+ */
+- (HBAudioTrack *)trackFromSourceTrackIndex:(NSInteger)index
 {
-    __block BOOL firsTrack = firstOnly;
-    [trackIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
-        // Add the track
-        [self _processPresetAudioArray: self.defaults.tracksArray forTrack:idx firstOnly:firsTrack];
-        firsTrack = self.defaults.secondaryEncoderMode ? YES : NO;
-    }];
+    HBAudioTrack *track = [[HBAudioTrack alloc] initWithTrackIdx:index container:self.container dataSource:self delegate:self];
+    track.undo = self.undo;
+    return track;
 }
 
-- (void)addTracksFromDefaults:(BOOL)allTracks
+#pragma mark - Defaults
+
+- (void)addTracksFromDefaults
 {
     BOOL firstTrack = NO;
+    BOOL allTracks = NO;
     NSMutableIndexSet *tracksAdded = [NSMutableIndexSet indexSet];
     NSMutableIndexSet *tracksToAdd = [NSMutableIndexSet indexSet];
 
     // Reinitialize the configured list of audio tracks
-    [self _clearAudioArray];
+    while (self.countOfTracks)
+    {
+        [self removeObjectFromTracksAtIndex:0];
+    }
 
     if (self.defaults.trackSelectionBehavior != HBAudioTrackSelectionBehaviorNone)
     {
         // Add tracks of Default and Alternate Language by name
         for (NSString *languageISOCode in self.defaults.trackSelectionLanguages)
         {
-            NSMutableIndexSet *tracksIndexes = [[self _tracksWithISOCode: languageISOCode
-                                                         selectOnlyFirst: self.defaults.trackSelectionBehavior == HBAudioTrackSelectionBehaviorFirst] mutableCopy];
+            NSMutableIndexSet *tracksIndexes = [[self _tracksWithISOCode:languageISOCode
+                                                         selectOnlyFirst:self.defaults.trackSelectionBehavior == HBAudioTrackSelectionBehaviorFirst] mutableCopy];
             [tracksIndexes removeIndexes:tracksAdded];
             if (tracksIndexes.count)
             {
@@ -229,7 +207,7 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
         }
 
         // If no preferred Language was found, add standard track 1
-        if (tracksAdded.count == 0 && self.masterTrackArray.count > 1)
+        if (tracksAdded.count == 0 && self.sourceTracks.count > 1)
         {
             [tracksToAdd addIndex:1];
         }
@@ -238,7 +216,7 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
     // If all tracks should be added, add all track numbers that are not yet processed
     if (allTracks)
     {
-        [tracksToAdd addIndexesInRange:NSMakeRange(1, self.masterTrackArray.count - 1)];
+        [tracksToAdd addIndexesInRange:NSMakeRange(1, self.sourceTracks.count - 1)];
         [tracksToAdd removeIndexes:tracksAdded];
     }
 
@@ -248,119 +226,131 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
     }
 
     // Add an None item
-    [self switchingTrackFromNone: nil];
+    [self addNoneTrack];
 }
 
-- (BOOL)anyCodecMatches:(int)codec
+/**
+ *  Uses the templateAudioArray from the preset to create the audios for the specified trackIndex.
+ *
+ *  @param templateAudioArray the track template.
+ *  @param trackIndex         the index of the source track.
+ *  @param firstOnly          use only the first track of the template or all.
+ */
+- (void)_processPresetAudioArray:(NSArray *)templateAudioArray forTrack:(NSUInteger)trackIndex firstOnly:(BOOL)firstOnly
 {
-    BOOL retval = NO;
-    NSUInteger audioArrayCount = [self countOfTracks];
-    for (NSUInteger i = 0; i < audioArrayCount && !retval; i++)
+    for (HBAudioTrackPreset *preset in templateAudioArray)
     {
-        HBAudioTrack *anAudio = [self objectInTracksAtIndex: i];
-        if ([anAudio enabled] && codec == [[anAudio codec][keyAudioCodec] intValue])
-        {
-            retval = YES;
-        }
-    }
-    return retval;
-}
-
-- (void)addNewAudioTrack
-{
-    HBAudioTrack *newAudio = [[HBAudioTrack alloc] init];
-    [newAudio setDataSource:self];
-    [newAudio setDelegate:self];
-    [self insertObject:newAudio inTracksAtIndex:[self countOfTracks]];
-    [newAudio setContainer:self.container];
-    [newAudio setTrack: self.noneTrack];
-    [newAudio setUndo:self.undo];
-}
+        HBAudioTrack *newAudio = [[HBAudioTrack alloc] initWithTrackIdx:trackIndex
+                                                              container:self.container
+                                                             dataSource:self
+                                                               delegate:self];
+        [newAudio setUndo:self.undo];
 
-#pragma mark -
-#pragma mark Notification Handling
+        [self insertObject:newAudio inTracksAtIndex:[self countOfTracks]];
 
-- (void)settingTrackToNone:(HBAudioTrack *)newNoneTrack
-{
-    // If this is not the last track in the array we need to remove it.  We then need to see if a new
-    // one needs to be added (in the case when we were at maximum count and this switching makes it
-    // so we are no longer at maximum.
-    NSUInteger index = [self.tracks indexOfObject: newNoneTrack];
+        int inputCodec = [self.sourceTracks[trackIndex][keyAudioInputCodec] intValue];
+        int outputCodec = preset.encoder;
 
-    if (NSNotFound != index && index < [self countOfTracks] - 1)
-    {
-        [self removeObjectFromTracksAtIndex: index];
-    }
-    [self switchingTrackFromNone: nil]; // see if we need to add one to the list
-}
+        // Check if we need to use a fallback
+         if (preset.encoder & HB_ACODEC_PASS_FLAG && !(preset.encoder & inputCodec & HB_ACODEC_PASS_MASK))
+         {
+             outputCodec = hb_audio_encoder_get_fallback_for_passthru(outputCodec);
+
+             // If we couldn't find an encoder for the passthru format
+             // fall back to the selected encoder fallback
+             if (outputCodec == HB_ACODEC_INVALID)
+             {
+                 outputCodec = self.defaults.encoderFallback;
+             }
+         }
+
+        int supportedMuxers = hb_audio_encoder_get_from_codec(outputCodec)->muxers;
+
+        // If our preset wants us to support a codec that the track does not support,
+        // instead of changing the codec we remove the audio instead.
+        if (supportedMuxers & self.container)
+        {
+            newAudio.drc = preset.drc;
+            newAudio.gain = preset.gain;
+            newAudio.mixdown = preset.mixdown;
+            newAudio.sampleRate = preset.sampleRate;
+            newAudio.bitRate = preset.bitRate;
+            newAudio.encoder = outputCodec;
+        }
+        else
+        {
+            [self removeObjectFromTracksAtIndex:[self countOfTracks] - 1];
+        }
 
-- (void)switchingTrackFromNone:(HBAudioTrack *)noLongerNoneTrack
-{
-    NSUInteger count = [self countOfTracks];
-    BOOL needToAdd = NO;
 
-    // If there is no last track that is None we add one.
-    if (0 < count)
-    {
-        HBAudioTrack *lastAudio = [self objectInTracksAtIndex: count - 1];
-        if ([lastAudio enabled])
+        if (firstOnly)
         {
-            needToAdd = YES;
+            break;
         }
     }
-    else
-    {
-        needToAdd = YES;
-    }
-
-    if (needToAdd)
-    {
-        [self addNewAudioTrack];
-    }
 }
 
-// This gets called whenever the video container changes.
-- (void)setContainer:(int)container
+/**
+ *  Matches the source audio tracks with the specific language iso code.
+ *
+ *  @param isoCode         the iso code to match.
+ *  @param selectOnlyFirst whether to match only the first track for the iso code.
+ *
+ *  @return a NSIndexSet with the index of the matched tracks.
+ */
+- (NSIndexSet *)_tracksWithISOCode:(NSString *)isoCode selectOnlyFirst:(BOOL)selectOnlyFirst
 {
-    _container = container;
+    NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
 
-    if (!(self.undo.isUndoing || self.undo.isRedoing))
-    {
-        // Update each of the instances because this value influences possible settings.
-        for (HBAudioTrack *audioObject in self.tracks)
+    [self.sourceTracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        if (idx) // Note that we skip the "None" track
         {
-            audioObject.container = container;
+            if ([isoCode isEqualToString:@"und"] ||  [obj[keyAudioTrackLanguageIsoCode] isEqualToString:isoCode])
+            {
+                [indexes addIndex:idx];
+
+                if (selectOnlyFirst)
+                {
+                    *stop = YES;
+                }
+            }
         }
+    }];
 
-        // Update the Auto Passthru Fallback Codec Popup
-        // lets get the tag of the currently selected item first so we might reset it later
-        [self.defaults validateEncoderFallbackForVideoContainer:container];
-    }
+    return indexes;
 }
 
-- (void)setUndo:(NSUndoManager *)undo
+- (void)_processPresetAudioArray:(NSArray<HBAudioTrackPreset *> *)templateAudioArray forTracks:(NSIndexSet *)trackIndexes firstOnly:(BOOL)firstOnly
 {
-    _undo = undo;
-    for (HBAudioTrack *track in self.tracks)
-    {
-        track.undo = undo;
-    }
-    self.defaults.undo = undo;
+    __block BOOL firstTrack = firstOnly;
+    [trackIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
+        // Add the track
+        [self _processPresetAudioArray: self.defaults.tracksArray forTrack:idx firstOnly:firstTrack];
+        firstTrack = self.defaults.secondaryEncoderMode ? YES : NO;
+    }];
 }
 
-- (void)setDefaults:(HBAudioDefaults *)defaults
+- (BOOL)anyCodecMatches:(int)codec
 {
-    if (defaults != _defaults)
+    BOOL retval = NO;
+    NSUInteger audioArrayCount = [self countOfTracks];
+    for (NSUInteger i = 0; i < audioArrayCount && !retval; i++)
     {
-        [[self.undo prepareWithInvocationTarget:self] setDefaults:_defaults];
+        HBAudioTrack *anAudio = [self objectInTracksAtIndex: i];
+        if (anAudio.isEnabled && codec == anAudio.encoder)
+        {
+            retval = YES;
+        }
     }
-    _defaults = defaults;
-    _defaults.undo = self.undo;
+    return retval;
 }
 
-- (void)mixdownChanged
+#pragma mark -
+#pragma mark Notification Handling
+
+- (void)encoderChanged
 {
-    [[NSNotificationCenter defaultCenter] postNotificationName: HBAudioChangedNotification object: self];
+    [[NSNotificationCenter defaultCenter] postNotificationName:HBAudioChangedNotification object:self];
 }
 
 #pragma mark - NSCopying
@@ -372,17 +362,13 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
     if (copy)
     {
         copy->_container = _container;
-
-        copy->_noneTrack = [_noneTrack copy];
-        copy->_masterTrackArray = [_masterTrackArray copy];
+        copy->_sourceTracks = [_sourceTracks mutableCopy];
 
         copy->_tracks = [[NSMutableArray alloc] init];
         [_tracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
             if (idx < _tracks.count)
             {
-                HBAudioTrack *trackCopy = [obj copy];
-                trackCopy.dataSource = copy;
-                trackCopy.delegate = copy;
+                id trackCopy = [obj copy];
                 [copy->_tracks addObject:trackCopy];
             }
         }];
@@ -402,14 +388,11 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
 
 - (void)encodeWithCoder:(NSCoder *)coder
 {
-    [coder encodeInt:1 forKey:@"HBAudioVersion"];
+    [coder encodeInt:2 forKey:@"HBAudioVersion"];
 
     encodeInt(_container);
-
-    encodeObject(_noneTrack);
-    encodeObject(_masterTrackArray);
+    encodeObject(_sourceTracks);
     encodeObject(_tracks);
-
     encodeObject(_defaults);
 }
 
@@ -418,9 +401,7 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
     self = [super init];
 
     decodeInt(_container);
-
-    decodeObject(_noneTrack, NSDictionary);
-    decodeObject(_masterTrackArray, NSArray);
+    decodeObject(_sourceTracks, NSMutableArray);
     decodeObject(_tracks, NSMutableArray);
 
     for (HBAudioTrack *track in _tracks)
@@ -444,13 +425,13 @@ NSString *HBAudioChangedNotification = @"HBAudioChangedNotification";
 - (void)applyPreset:(HBPreset *)preset
 {
     [self.defaults applyPreset:preset];
-    [self addTracksFromDefaults:NO];
+    [self addTracksFromDefaults];
 }
 
 #pragma mark -
 #pragma mark KVC
 
-- (NSUInteger) countOfTracks
+- (NSUInteger)countOfTracks
 {
     return self.tracks.count;
 }
index c259812e81724eaa4a78f9a40a55f2af922b5009..b0a5e0bea28697e0847a81f6a85bc9756322fabe 100644 (file)
@@ -22,51 +22,50 @@ extern NSString *keyAudioInputCodecParam;
 extern NSString *keyAudioInputChannelLayout;
 extern NSString *keyAudioTrackLanguageIsoCode;
 
-extern NSString *keyAudioCodecName;
-extern NSString *keyAudioSampleRateName;
-extern NSString *keyAudioBitrateName;
-extern NSString *keyAudioMixdownName;
-extern NSString *keyAudioCodec;
-extern NSString *keyAudioMixdown;
-extern NSString *keyAudioSamplerate;
-extern NSString *keyAudioBitrate;
-
 @protocol HBAudioTrackDataSource <NSObject>
-- (NSDictionary *)noneTrack;
-- (NSArray *)masterTrackArray;
+- (NSDictionary<NSString *, id> *)sourceTrackAtIndex:(NSUInteger)idx;
+- (NSArray<NSString *> *)sourceTracksArray;
 @end
 
 @protocol HBAudioTrackDelegate <NSObject>
-- (void)settingTrackToNone:(HBAudioTrack *)newNoneTrack;
-- (void)switchingTrackFromNone:(HBAudioTrack *)noLongerNoneTrack;
-- (void)mixdownChanged;
+- (void)track:(HBAudioTrack *)track didChangeSourceFrom:(NSUInteger)oldSourceIdx;
+- (void)encoderChanged;
 @end
 
 @interface HBAudioTrack : NSObject <NSSecureCoding, NSCopying>
 
-@property (nonatomic, strong) NSDictionary *track;
-@property (nonatomic, strong, nullable) NSDictionary *codec;
-@property (nonatomic, strong, nullable) NSDictionary *mixdown;
-@property (nonatomic, strong, nullable) NSDictionary *sampleRate;
-@property (nonatomic, strong, nullable) NSDictionary *bitRate;
-@property (nonatomic) double drc;
-@property (nonatomic) double gain;
-@property (nonatomic) int container;
+- (instancetype)initWithTrackIdx:(NSUInteger)index
+                       container:(int)container
+                      dataSource:(id<HBAudioTrackDataSource>)dataSource
+                        delegate:(id<HBAudioTrackDelegate>)delegate;
+
+/// The index of the source in the data source tracks array.
+@property (nonatomic, readwrite) NSUInteger sourceTrackIdx;
+@property (nonatomic, readwrite) int container;
 
 @property (nonatomic, weak, nullable) id<HBAudioTrackDataSource> dataSource;
 @property (nonatomic, weak, nullable) id<HBAudioTrackDelegate> delegate;
 
-@property (nonatomic, readonly) NSArray *codecs;
-@property (nonatomic, readonly) NSArray *mixdowns;
-@property (nonatomic, readonly) NSArray *sampleRates;
-@property (nonatomic, readonly) NSArray *bitRates;
-@property (nonatomic, readonly) BOOL enabled;
-
-- (void) setTrackFromIndex: (int) aValue;
-- (BOOL) setCodecFromName: (nullable NSString *) aValue;
-- (void) setMixdownFromName: (NSString *) aValue;
-- (void) setSampleRateFromName: (NSString *) aValue;
-- (void) setBitRateFromName: (NSString *) aValue;
+/**
+ *  track properties.
+ */
+@property (nonatomic, readwrite) int encoder;
+@property (nonatomic, readwrite) int mixdown;
+@property (nonatomic, readwrite) int sampleRate;
+@property (nonatomic, readwrite) int bitRate;
+
+@property (nonatomic, readwrite) double gain;
+@property (nonatomic, readwrite) double drc;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+
+/**
+ *  Arrays of possible options for the track properties.
+ */
+@property (nonatomic, readonly) NSArray<NSString *> *encoders;
+@property (nonatomic, readonly) NSArray<NSString *> *mixdowns;
+@property (nonatomic, readonly) NSArray<NSString *> *sampleRates;
+@property (nonatomic, readonly) NSArray<NSString *> *bitRates;
 
 @property (nonatomic, readwrite, weak, nullable) NSUndoManager *undo;
 
index 1c998cc4f3a051e20b29f526711bd40d255fb14a..9e93eab5d2dfe461b3924b2b3729930480ff1661 100644 (file)
@@ -19,339 +19,95 @@ NSString *keyAudioInputCodecParam = @"keyAudioInputCodecParam";
 NSString *keyAudioInputChannelLayout = @"keyAudioInputChannelLayout";
 NSString *keyAudioTrackLanguageIsoCode = @"keyAudioTrackLanguageIsoCode";
 
-NSString *keyAudioCodecName = @"keyAudioCodecName";
-NSString *keyAudioSupportedMuxers = @"keyAudioSupportedMuxers";
-NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
-NSString *keyAudioBitrateName = @"keyAudioBitrateName";
-NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
-NSString *keyAudioMixdownName = @"keyAudioMixdownName";
-
-NSString *keyAudioCodec = @"codec";
-NSString *keyAudioMixdown = @"mixdown";
-NSString *keyAudioSamplerate = @"samplerate";
-NSString *keyAudioBitrate = @"bitrate";
-
-static NSMutableArray *masterCodecArray = nil;
-static NSMutableArray *masterMixdownArray = nil;
-static NSMutableArray *masterBitRateArray = nil;
-
-@interface NSArray (HBAudioSupport)
-- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
-- (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
-@end
-@implementation NSArray (HBAudioSupport)
-- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey reverse: (BOOL) reverse
-{
-    NSDictionary *retval = nil;
-    NSEnumerator *enumerator = reverse ? [self reverseObjectEnumerator] : [self objectEnumerator];
-    NSDictionary *dict;
-    id aValue;
-
-    while (nil != (dict = [enumerator nextObject]) && !retval)
-    {
-        if (nil != (aValue = dict[aKey]) && [aValue isEqual: anObject])
-        {
-            retval = dict;
-        }
-    }
-    return retval;
-}
-- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
-{
-    return [self dictionaryWithObject: anObject matchingKey: aKey reverse: NO];
-}
-- (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
-{
-    return [self dictionaryWithObject: anObject matchingKey: aKey reverse: YES];
-}
-
-@end
+#define DEFAULT_SAMPLERATE 48000
 
 @interface HBAudioTrack ()
-
-@property (nonatomic, readwrite) NSArray *codecs;
-@property (nonatomic, readwrite) NSArray *mixdowns;
-@property (nonatomic, readwrite) NSArray *bitRates;
-
+@property (nonatomic, readwrite) BOOL validating;
 @end
 
 @implementation HBAudioTrack
 
-#pragma mark -
-#pragma mark Object Setup
-
-+ (void)initialize
+- (instancetype)init
 {
-    if ([HBAudioTrack class] == self)
+    self = [super init];
+    if (self)
     {
-        masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
-             audio_encoder != NULL;
-             audio_encoder  = hb_audio_encoder_get_next(audio_encoder))
-        {
-            id audioMustMatchTrack;
-            if ((audio_encoder->codec &  HB_ACODEC_PASS_FLAG) &&
-                (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
-            {
-                audioMustMatchTrack = @(audio_encoder->codec &
-                                                      ~HB_ACODEC_PASS_FLAG);
-            }
-            else
-            {
-                audioMustMatchTrack = @NO;
-            }
-            [masterCodecArray addObject:@{keyAudioCodecName:       @(audio_encoder->name),
-                                          keyAudioCodec:           @(audio_encoder->codec),
-                                          keyAudioSupportedMuxers: @(audio_encoder->muxers),
-                                          keyAudioMustMatchTrack:    audioMustMatchTrack}];
-        }
-
-        masterMixdownArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL);
-             mixdown != NULL;
-             mixdown  = hb_mixdown_get_next(mixdown))
-        {
-            [masterMixdownArray addObject:@{keyAudioMixdownName: @(mixdown->name),
-                                            keyAudioMixdown:     @(mixdown->amixdown)}];
-        }
-
-        masterBitRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL);
-             audio_bitrate != NULL;
-             audio_bitrate  = hb_audio_bitrate_get_next(audio_bitrate))
-        {
-            [masterBitRateArray addObject:@{keyAudioBitrateName: @(audio_bitrate->name),
-                                            keyAudioBitrate:     @(audio_bitrate->rate)}];
-        }
+        // Defaults settings
+        _encoder = HB_ACODEC_CA_AAC;
+        _container = HB_MUX_MKV;
+        _sampleRate = 0;
+        _bitRate = 160;
+        _mixdown = HB_AMIXDOWN_DOLBYPLII;
     }
+    return self;
 }
 
-// Ensure the list of codecs is accurate
-// Update the current value of codec based on the revised list
-- (void) updateCodecs
+- (instancetype)initWithTrackIdx:(NSUInteger)index
+                       container:(int)container
+                      dataSource:(id<HBAudioTrackDataSource>)dataSource
+                        delegate:(id<HBAudioTrackDelegate>)delegate;
 {
-    NSMutableArray *permittedCodecs = [NSMutableArray array];
-    NSUInteger count = [masterCodecArray count];
-    NSDictionary *dict;
-
-    // First get a list of the permitted codecs based on the internal rules
-    if (nil != self.track && self.enabled)
+    self = [super init];
+    if (self)
     {
-        BOOL goodToAdd;
-
-        for (unsigned int i = 0; i < count; i++)
-        {
-            dict = masterCodecArray[i];
-
-            // First make sure only codecs permitted by the container are here
-            goodToAdd = !!([dict[keyAudioSupportedMuxers] intValue] & self.container);
+        _dataSource = dataSource;
+        _sourceTrackIdx = index;
+        _container = container;
 
-            // 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
-            if ([dict[keyAudioMustMatchTrack] boolValue])
-            {
-                if ([dict[keyAudioMustMatchTrack] intValue] != [self.track[keyAudioInputCodec] intValue])
-                {
-                    goodToAdd = NO;
-                }
-            }
+        [self validateSettings];
 
-            if (goodToAdd)
-            {
-                [permittedCodecs addObject: dict];
-            }
-        }
+        _delegate = delegate;
     }
 
-    // Now make sure the permitted list and the actual ones matches
-    [self setCodecs: permittedCodecs];
+    return self;
+}
 
-    // Ensure our codec is on the list of permitted codecs
-    if (!self.codec || ![permittedCodecs containsObject: self.codec])
+- (void)validateSettings
+{
+    if (_sourceTrackIdx)
     {
-        if (0 < [permittedCodecs count])
+        if (self.encoder == 0)
         {
-            self.codec = permittedCodecs[0]; // This should be defaulting to Core Audio
+            self.encoder = HB_ACODEC_CA_AAC;
+            self.bitRate = 160;
         }
         else
         {
-            self.codec = nil;
+            self.encoder = [self sanatizeEncoderValue:self.encoder];
         }
     }
-}
-
-- (void)updateMixdowns:(BOOL)shouldSetDefault
-{
-    NSMutableArray *permittedMixdowns = [NSMutableArray array];
-    NSDictionary *dict;
-    int currentMixdown;
-
-    unsigned long long channelLayout = [self.track[keyAudioInputChannelLayout] unsignedLongLongValue];
-    NSUInteger count                 = [masterMixdownArray count];
-    int codecCodec                   = [self.codec[keyAudioCodec] intValue];
-    int theDefaultMixdown            = hb_mixdown_get_default(codecCodec, channelLayout);
-
-    for (unsigned int i = 0; i < count; i++)
-    {
-        dict = masterMixdownArray[i];
-        currentMixdown = [dict[keyAudioMixdown] intValue];
-
-        if (hb_mixdown_is_supported(currentMixdown, codecCodec, channelLayout))
-        {
-            [permittedMixdowns addObject: dict];
-        }
-    }
-
-    if (!self.enabled)
-    {
-        permittedMixdowns = nil;
-    }
-
-    // Now make sure the permitted list and the actual ones matches
-    self.mixdowns = permittedMixdowns;
-
-    // Select the proper one
-    if (shouldSetDefault)
-    {
-        self.mixdown = [permittedMixdowns dictionaryWithObject: @(theDefaultMixdown)
-                                                      matchingKey: keyAudioMixdown];
-    }
-
-    if (!self.mixdown || ![permittedMixdowns containsObject: self.mixdown])
+    else
     {
-        self.mixdown = [permittedMixdowns lastObject];
+        self.encoder = 0;
+        self.mixdown = 0;
+        self.sampleRate = 0;
+        self.bitRate = -1;
     }
 }
 
-- (void)validateSamplerate
-{
-    int codec      = [self.codec[keyAudioCodec] intValue];
-    int samplerate = [self.sampleRate[keyAudioSamplerate] intValue];
+#pragma mark - Track properties
 
-    if (codec & HB_ACODEC_PASS_FLAG)
-    {
-        [self setSampleRateFromName:@"Auto"];
-    }
-    else if (samplerate)
-    {
-        samplerate = hb_audio_samplerate_find_closest(samplerate, codec);
-        [self setSampleRateFromName:@(hb_audio_samplerate_get_name(samplerate))];
-    }
-}
-
-- (void)updateBitRates:(BOOL)shouldSetDefault
+- (void)setSourceTrackIdx:(NSUInteger)sourceTrackIdx
 {
-    NSMutableArray *permittedBitRates = [NSMutableArray array];
-    NSDictionary *dict;
-    int minBitRate;
-    int maxBitRate;
-    int currentBitRate;
-    BOOL shouldAdd;
-
-    NSUInteger count = [masterBitRateArray count];
-    int trackInputBitRate = [self.track[keyAudioInputBitrate] intValue];
-    int theSampleRate = [self.sampleRate[keyAudioSamplerate] intValue];
-
-    if (0 == theSampleRate) // this means Auto
+    if (sourceTrackIdx != _sourceTrackIdx)
     {
-        theSampleRate = [self.track[keyAudioInputSampleRate] intValue];
+        [[self.undo prepareWithInvocationTarget:self] setSourceTrackIdx:_sourceTrackIdx];
     }
 
-    int ourCodec          = [self.codec[keyAudioCodec] intValue];
-    int ourMixdown        = [self.mixdown[keyAudioMixdown] intValue];
-    int theDefaultBitRate = hb_audio_bitrate_get_default(ourCodec, theSampleRate, ourMixdown);
-    hb_audio_bitrate_get_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
-
-    BOOL codecIsPassthru = ([self.codec[keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO;
-    BOOL codecIsLossless = (theDefaultBitRate == -1) ? YES : NO;
-
-    if (codecIsPassthru)
-    {
-        NSDictionary *sourceBitRate = [masterBitRateArray dictionaryWithObject: @(trackInputBitRate)
-                                                                   matchingKey: keyAudioBitrate];
-        if (!sourceBitRate)
-        {
-            // the source bitrate isn't in the master array - create it
-            sourceBitRate = @{keyAudioBitrateName: [NSString stringWithFormat: @"%d", trackInputBitRate],
-                              keyAudioBitrate: @(trackInputBitRate)};
-        }
-        [permittedBitRates addObject: sourceBitRate];
-    }
-    else if (codecIsLossless)
-    {
-        NSDictionary *bitRateNotApplicable = @{keyAudioBitrateName: @"N/A",
-                                               keyAudioBitrate: @-1};
-        [permittedBitRates addObject: bitRateNotApplicable];
-    }
-    else
-    {
-        for (unsigned int i = 0; i < count; i++)
-        {
-            dict = masterBitRateArray[i];
-            currentBitRate = [dict[keyAudioBitrate] intValue];
-
-            // First ensure the bitrate falls within range of the codec
-            shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate);
-
-            if (shouldAdd)
-            {
-                [permittedBitRates addObject: dict];
-            }
-        }
-    }
-
-    if (!self.enabled)
-    {
-        permittedBitRates = nil;
-    }
-
-    // Make sure we are updated with the permitted list
-    self.bitRates = permittedBitRates;
-
-    // Select the proper one
-    if (shouldSetDefault)
-    {
-        [self setBitRateFromName: [NSString stringWithFormat:@"%d", theDefaultBitRate]];
-    }
+    NSUInteger oldIdx = _sourceTrackIdx;
+    _sourceTrackIdx = sourceTrackIdx;
 
-    if (!self.bitRate || ![permittedBitRates containsObject: self.bitRate])
+    if (!(self.undo.isUndoing || self.undo.isRedoing))
     {
-        self.bitRate = [permittedBitRates lastObject];
-    }
-}
-
-#pragma mark -
-#pragma mark Accessors
+        [self validateSettings];
 
-- (NSArray *)sampleRates
-{
-    NSMutableArray *samplerates = [[NSMutableArray alloc] init];
-
-    /*
-     * Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
-     * input sample rate when it finds this 0 value as the selected sample rate.  We do this because the input
-     * sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
-     */
-    [samplerates addObject:@{keyAudioSampleRateName: @"Auto",
-                             keyAudioSamplerate:     @0}];
-
-    int codec = [self.codec[keyAudioCodec] intValue];
-    for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL);
-         audio_samplerate != NULL;
-         audio_samplerate  = hb_audio_samplerate_get_next(audio_samplerate))
-    {
-        int rate = audio_samplerate->rate;
-        if (rate == hb_audio_samplerate_find_closest(rate, codec))
+        if (oldIdx != sourceTrackIdx)
         {
-            [samplerates addObject:@{keyAudioSampleRateName: @(audio_samplerate->name),
-                                     keyAudioSamplerate:     @(rate)}];
+            [self.delegate track:self didChangeSourceFrom:oldIdx];
         }
     }
-    return samplerates;
 }
 
-#pragma mark -
-#pragma mark Setters
-
 - (void)setContainer:(int)container
 {
     if (container != _container)
@@ -362,54 +118,33 @@ static NSMutableArray *masterBitRateArray = nil;
 
     if (!(self.undo.isUndoing || self.undo.isRedoing))
     {
-        [self updateCodecs];
-    }
-}
-
-- (void)setTrack:(NSDictionary *)track
-{
-    if (track != _track)
-    {
-        [[self.undo prepareWithInvocationTarget:self] setTrack:_track];
-    }
-    NSDictionary *oldValue = _track;
-    _track = track;
-    if (nil != _track && !(self.undo.isUndoing || self.undo.isRedoing))
-    {
-        [self updateCodecs];
-        [self updateMixdowns: YES];
-        if (self.enabled)
-        {
-            self.sampleRate = self.sampleRates[0]; // default to Auto
-        }
-        if ([self.dataSource.noneTrack isEqual: oldValue])
-        {
-            [self.delegate switchingTrackFromNone: self];
-        }
-        if ([self.dataSource.noneTrack isEqual: self.track])
+        if (self.encoder)
         {
-            [self.delegate settingTrackToNone: self];
+            self.encoder = [self sanatizeEncoderValue:self.encoder];
         }
     }
 }
 
-- (void)setCodec:(NSDictionary *)codec
+- (void)setEncoder:(int)encoder
 {
-    if (codec != _codec)
+    if (encoder != _encoder)
     {
-        [[self.undo prepareWithInvocationTarget:self] setCodec:_codec];
+        [[self.undo prepareWithInvocationTarget:self] setEncoder:_encoder];
     }
-    _codec = codec;
+    _encoder = encoder;
 
-    if (!(self.undo.isUndoing || self.undo.isRedoing))
+    if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating)
     {
-        [self validateSamplerate];
-        [self updateMixdowns:YES];
-        [self updateBitRates:YES];
+        self.validating = YES;
+        [self.delegate encoderChanged];
+        self.mixdown = [self sanatizeMixdownValue:self.mixdown];
+        self.sampleRate = [self sanatizeSamplerateValue:self.sampleRate];
+        self.bitRate = [self sanatizeBitrateValue:self.bitRate];
+        self.validating = NO;
     }
 }
 
-- (void)setMixdown:(NSDictionary *)mixdown
+- (void)setMixdown:(int)mixdown
 {
     if (mixdown != _mixdown)
     {
@@ -417,14 +152,15 @@ static NSMutableArray *masterBitRateArray = nil;
     }
     _mixdown = mixdown;
 
-    if (!(self.undo.isUndoing || self.undo.isRedoing))
+    if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating)
     {
-        [self updateBitRates:YES];
-        [self.delegate mixdownChanged];
+        self.validating = YES;
+        self.bitRate = [self sanatizeBitrateValue:self.bitRate];
+        self.validating = NO;
     }
 }
 
-- (void)setSampleRate:(NSDictionary *)sampleRate
+- (void)setSampleRate:(int)sampleRate
 {
     if (sampleRate != _sampleRate)
     {
@@ -432,13 +168,15 @@ static NSMutableArray *masterBitRateArray = nil;
     }
     _sampleRate = sampleRate;
 
-    if (!(self.undo.isUndoing || self.undo.isRedoing))
+    if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating)
     {
-        [self updateBitRates: NO];
+        self.validating = YES;
+        self.bitRate = [self sanatizeBitrateValue:self.bitRate];
+        self.validating = NO;
     }
 }
 
-- (void)setBitRate:(NSDictionary *)bitRate
+- (void)setBitRate:(int)bitRate
 {
     if (bitRate != _bitRate)
     {
@@ -447,15 +185,6 @@ static NSMutableArray *masterBitRateArray = nil;
     _bitRate = bitRate;
 }
 
-- (void)setDrc:(double)drc
-{
-    if (drc != _drc)
-    {
-        [[self.undo prepareWithInvocationTarget:self] setDrc:_drc];
-    }
-    _drc = drc;
-}
-
 - (void)setGain:(double)gain
 {
     if (gain != _gain)
@@ -465,140 +194,235 @@ static NSMutableArray *masterBitRateArray = nil;
     _gain = gain;
 }
 
-#pragma mark -
-#pragma mark Special Setters
-
-- (void)setTrackFromIndex:(int)aValue
+// Because we have indicated that the binding for the gain validates immediately we can implement the
+// key value binding method to ensure the gain stays in our accepted range.
+- (BOOL)validateGain:(id *)ioValue error:(NSError * __autoreleasing *)outError
 {
-    self.track = [self.dataSource.masterTrackArray dictionaryWithObject: @(aValue)
-                                                            matchingKey: keyAudioTrackIndex];
+    BOOL retval = YES;
+
+    if (nil != *ioValue)
+    {
+        if ([*ioValue intValue] < -20)
+        {
+            *ioValue = @(-20);
+        }
+        else if ([*ioValue intValue] > 20)
+        {
+            *ioValue = @20;
+        }
+    }
+
+    return retval;
 }
 
-// This returns whether it is able to set the actual codec desired.
-- (BOOL)setCodecFromName:(NSString *)aValue
+- (void)setDrc:(double)drc
 {
-    NSDictionary *dict = [self.codecs dictionaryWithObject: aValue matchingKey: keyAudioCodecName];
-    if (nil != dict)
+    if (drc != _drc)
     {
-        self.codec = dict;
+        [[self.undo prepareWithInvocationTarget:self] setDrc:_drc];
     }
-    return (nil != dict);
+    _drc = drc;
 }
 
-- (void)setMixdownFromName:(NSString *)aValue
+#pragma mark - Validation
+
+- (int)sanatizeEncoderValue:(int)proposedEncoder
 {
-    NSDictionary *dict = [self.mixdowns dictionaryWithObject: aValue matchingKey: keyAudioMixdownName];
-    if (nil != dict)
+    if (proposedEncoder)
+    {
+        NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx];
+        int inputCodec = [sourceTrack[keyAudioInputCodec] intValue];
+
+        hb_encoder_t *proposedEncoderInfo = hb_audio_encoder_get_from_codec(proposedEncoder);
+
+        if (proposedEncoderInfo && proposedEncoderInfo->muxers & self.container)
+        {
+            // If the codec is passthru, see if the new source supports it.
+            if (proposedEncoderInfo->codec & HB_ACODEC_PASS_FLAG)
+            {
+                if ((proposedEncoderInfo->codec & inputCodec & HB_ACODEC_PASS_MASK))
+                {
+                    return proposedEncoder;
+                }
+            }
+            else
+            {
+                return proposedEncoder;
+            }
+        }
+
+        return HB_ACODEC_CA_AAC;
+    }
+    else
     {
-        self.mixdown = dict;
+        return proposedEncoder;
     }
 }
 
-- (void)setSampleRateFromName:(NSString *)aValue
+- (int)sanatizeMixdownValue:(int)proposedMixdown
 {
-    NSDictionary *dict = [self.sampleRates dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName];
-    if (nil != dict)
+    NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx];
+    unsigned long long channelLayout = [sourceTrack[keyAudioInputChannelLayout] unsignedLongLongValue];
+
+    if (!hb_mixdown_is_supported(proposedMixdown, self.encoder, channelLayout))
     {
-        self.sampleRate = dict;
+        return hb_mixdown_get_default(self.encoder, channelLayout);
     }
+    return proposedMixdown;
 }
 
-- (void)setBitRateFromName:(NSString *)aValue
+- (int)sanatizeSamplerateValue:(int)proposedSamplerate
 {
-    NSDictionary *dict = [self.bitRates dictionaryWithObject: aValue matchingKey: keyAudioBitrateName];
-    if (nil != dict)
+    if (self.encoder & HB_ACODEC_PASS_FLAG)
+    {
+        return 0; // Auto (same as source)
+    }
+    else if (proposedSamplerate)
     {
-        self.bitRate = dict;
+        return hb_audio_samplerate_find_closest(proposedSamplerate, self.encoder);
     }
+    return proposedSamplerate;
 }
 
-- (void)setCodecs:(NSArray *)codecs
+- (int)sanatizeBitrateValue:(int)proposedBitrate
 {
-    if (codecs != _codecs)
+    if (self.encoder & HB_ACODEC_PASS_FLAG)
     {
-        [[self.undo prepareWithInvocationTarget:self] setCodecs:_codecs];
+        return -1;
+    }
+    else if (proposedBitrate == -1) // switching from passthru
+    {
+        return hb_audio_bitrate_get_default(self.encoder,
+                                            self.sampleRate ? self.sampleRate : DEFAULT_SAMPLERATE,
+                                            self.mixdown);
+    }
+    else
+    {
+        return hb_audio_bitrate_get_best(self.encoder, proposedBitrate, self.sampleRate, self.mixdown);
     }
-    _codecs = codecs;
 }
 
-- (void)setMixdowns:(NSArray *)mixdowns
+#pragma mark - Options
+
+- (NSArray<NSString *> *)encoders
 {
-    if (mixdowns != _mixdowns)
+    NSMutableArray<NSString *> *encoders = [[NSMutableArray alloc] init];
+
+    NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx];
+    int inputCodec = [sourceTrack[keyAudioInputCodec] intValue];
+
+    for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
+         audio_encoder != NULL;
+         audio_encoder  = hb_audio_encoder_get_next(audio_encoder))
     {
-        [[self.undo prepareWithInvocationTarget:self] setMixdowns:_mixdowns];
+        if (audio_encoder->muxers & self.container)
+        {
+            if (audio_encoder->codec & HB_ACODEC_PASS_FLAG)
+            {
+                // If the codec is passthru, show only the supported ones.
+                if ((audio_encoder->codec & inputCodec & HB_ACODEC_PASS_MASK))
+                {
+                    [encoders addObject:@(audio_encoder->name)];
+                }
+            }
+            else
+            {
+                [encoders addObject:@(audio_encoder->name)];
+            }
+        }
     }
-    _mixdowns = mixdowns;
+    return encoders;
 }
 
-- (void)setBitRates:(NSArray *)bitRates
+- (NSArray<NSString *> *)mixdowns
 {
-    if (bitRates != _bitRates)
+    NSMutableArray<NSString *> *mixdowns = [[NSMutableArray alloc] init];
+
+    NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx];
+    unsigned long long channelLayout = [sourceTrack[keyAudioInputChannelLayout] unsignedLongLongValue];
+
+    for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL);
+         mixdown != NULL;
+         mixdown  = hb_mixdown_get_next(mixdown))
     {
-        [[self.undo prepareWithInvocationTarget:self] setBitRates:_bitRates];
+        if (hb_mixdown_is_supported(mixdown->amixdown, self.encoder, channelLayout))
+        {
+            [mixdowns addObject:@(mixdown->name)];
+        }
     }
-    _bitRates = bitRates;
+    return mixdowns;
 }
 
-#pragma mark -
-#pragma mark Validation
-
-// Because we have indicated that the binding for the gain validates immediately we can implement the
-// key value binding method to ensure the gain stays in our accepted range.
-- (BOOL)validateGain:(id *)ioValue error:(NSError * __autoreleasing *)outError
+- (NSArray<NSString *> *)sampleRates
 {
-    BOOL retval = YES;
+    NSMutableArray<NSString *> *sampleRates = [[NSMutableArray alloc] init];
+    [sampleRates addObject:@"Auto"];
 
-    if (nil != *ioValue)
+    for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL);
+         audio_samplerate != NULL;
+         audio_samplerate  = hb_audio_samplerate_get_next(audio_samplerate))
     {
-        if ([*ioValue intValue] < -20)
+        int rate = audio_samplerate->rate;
+        if (rate == hb_audio_samplerate_find_closest(rate, self.encoder))
         {
-            *ioValue = @(-20);
+            [sampleRates addObject:@(audio_samplerate->name)];
         }
-        else if ([*ioValue intValue] > 20)
+    }
+    return sampleRates;
+}
+
+- (NSArray<NSString *> *)bitRates
+{
+    int minBitRate = 0;
+    int maxBitRate = 0;
+
+    hb_audio_bitrate_get_limits(self.encoder, self.sampleRate, self.mixdown, &minBitRate, &maxBitRate);
+
+    NSMutableArray<NSString *> *bitRates = [[NSMutableArray alloc] init];
+    for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL);
+         audio_bitrate != NULL;
+         audio_bitrate  = hb_audio_bitrate_get_next(audio_bitrate))
+    {
+        if (audio_bitrate->rate >= minBitRate && audio_bitrate->rate <= maxBitRate)
         {
-            *ioValue = @20;
+            [bitRates addObject:@(audio_bitrate->name)];
         }
     }
-
-    return retval;
+    return bitRates;
 }
 
-#pragma mark - Bindings Support
+#pragma mark - KVO UI Additions
 
-- (NSArray *)masterTrackArray
+- (NSArray *)sourceTracksArray
 {
-    return self.dataSource.masterTrackArray;
+    return [self.dataSource sourceTracksArray];
 }
 
-- (BOOL)enabled
+- (BOOL)isEnabled
 {
-    return (nil != self.track) ? (![self.track isEqual: self.dataSource.noneTrack]) : NO;
+    return self.sourceTrackIdx != 0;
 }
 
 - (BOOL)mixdownEnabled
 {
-    BOOL retval = self.enabled;
+    BOOL retval = self.isEnabled;
 
-    if (retval)
+    if (retval && self.mixdown == HB_AMIXDOWN_NONE)
     {
-        int myMixdown = [self.mixdown[keyAudioMixdown] intValue];
-        if (myMixdown == HB_AMIXDOWN_NONE)
-        {
-            // "None" mixdown (passthru)
-            retval = NO;
-        }
+        // "None" mixdown (passthru)
+        retval = NO;
     }
+
     return retval;
 }
 
 - (BOOL)bitrateEnabled
 {
-    BOOL retval = self.enabled;
+    BOOL retval = self.isEnabled;
 
     if (retval)
     {
-        int myCodecCodec          = [self.codec[keyAudioCodec] intValue];
-        int myCodecDefaultBitrate = hb_audio_bitrate_get_default(myCodecCodec, 0, 0);
+        int myCodecDefaultBitrate = hb_audio_bitrate_get_default(self.encoder, 0, 0);
         if (myCodecDefaultBitrate < 0)
         {
             retval = NO;
@@ -607,16 +431,17 @@ static NSMutableArray *masterBitRateArray = nil;
     return retval;
 }
 
-- (BOOL)DRCEnabled
+- (BOOL)drcEnabled
 {
-    BOOL retval = self.enabled;
+    BOOL retval = self.isEnabled;
 
     if (retval)
     {
-        int myTrackParam = [self.track[keyAudioInputCodecParam] intValue];
-        int myTrackCodec = [self.track[keyAudioInputCodec] intValue];
-        int myCodecCodec = [self.codec[keyAudioCodec] intValue];
-        if (!hb_audio_can_apply_drc(myTrackCodec, myTrackParam, myCodecCodec))
+        NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx];
+
+        int inputCodec = [sourceTrack[keyAudioInputCodec] intValue];
+        int inputCodecParam = [sourceTrack[keyAudioInputCodecParam] intValue];
+        if (!hb_audio_can_apply_drc(inputCodec, inputCodecParam, self.encoder))
         {
             retval = NO;
         }
@@ -624,52 +449,46 @@ static NSMutableArray *masterBitRateArray = nil;
     return retval;
 }
 
-- (BOOL)PassThruDisabled
+- (BOOL)passThruDisabled
 {
-    BOOL retval = self.enabled;
+    BOOL retval = YES;
 
-    if (retval)
+    if (self.encoder & HB_ACODEC_PASS_FLAG)
     {
-        int myCodecCodec = [self.codec[keyAudioCodec] intValue];
-        if (myCodecCodec & HB_ACODEC_PASS_FLAG)
-        {
-            retval = NO;
-        }
+        retval = NO;
     }
+
     return retval;
 }
 
-- (void)setNilValueForKey:(NSString *)key
-{
-    if ([key isEqualToString:@"drc"] || [key isEqualToString:@"gain"])
-    {
-        [self setValue:@0 forKey:key];
-    }
-}
+#pragma mark - KVO
 
 + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
 {
     NSSet *retval = nil;
 
-    if ([key isEqualToString:@"enabled"])
+    if ([key isEqualToString:@"bitrateEnabled"] ||
+        [key isEqualToString:@"passThruDisabled"] ||
+        [key isEqualToString:@"mixdownEnabled"])
     {
-        retval = [NSSet setWithObjects:@"track", nil];
+        retval = [NSSet setWithObjects:@"encoder", nil];
     }
-    else if ([key isEqualToString:@"PassThruDisabled"])
+    else if ([key isEqualToString:@"mixdowns"] ||
+             [key isEqualToString:@"drcEnabled"])
     {
-        retval = [NSSet setWithObjects:@"track", @"codec", nil];
+        retval = [NSSet setWithObjects:@"sourceTrackIdx", @"encoder", nil];
     }
-    else if ([key isEqualToString:@"DRCEnabled"])
+    else if ([key isEqualToString:@"sampleRates"])
     {
-        retval = [NSSet setWithObjects:@"track", @"codec", nil];
+        retval = [NSSet setWithObjects:@"encoder", @"mixdown", nil];
     }
-    else if ([key isEqualToString:@"bitrateEnabled"])
+    else if ([key isEqualToString:@"bitRates"])
     {
-        retval = [NSSet setWithObjects:@"track", @"codec", nil];
+        retval = [NSSet setWithObjects:@"encoder", @"mixdown", @"sampleRate", nil];
     }
-    else if ([key isEqualToString:@"mixdownEnabled"])
+    else if ([key isEqualToString:@"encoders"])
     {
-        retval = [NSSet setWithObjects:@"track", @"mixdown", nil];
+        retval = [NSSet setWithObjects:@"container", @"sourceTrackIdx", nil];
     }
     else
     {
@@ -679,6 +498,14 @@ static NSMutableArray *masterBitRateArray = nil;
     return retval;
 }
 
+- (void)setNilValueForKey:(NSString *)key
+{
+    if ([key isEqualToString:@"drc"] || [key isEqualToString:@"gain"])
+    {
+        [self setValue:@0 forKey:key];
+    }
+}
+
 #pragma mark - NSCopying
 
 - (instancetype)copyWithZone:(NSZone *)zone
@@ -687,18 +514,16 @@ static NSMutableArray *masterBitRateArray = nil;
 
     if (copy)
     {
-        copy->_track = [_track copy];
-        copy->_codec = [_codec copy];
-        copy->_mixdown = [_mixdown copy];
-        copy->_sampleRate = [_sampleRate copy];
-        copy->_bitRate = [_bitRate copy];
-        copy->_drc = _drc;
-        copy->_gain = _gain;
+        copy->_sourceTrackIdx = _sourceTrackIdx;
         copy->_container = _container;
 
-        copy->_codecs = [_codecs copy];
-        copy->_mixdowns = [_mixdowns copy];
-        copy->_bitRates = [_bitRates copy];
+        copy->_encoder = _encoder;
+        copy->_mixdown = _mixdown;
+        copy->_sampleRate = _sampleRate;
+        copy->_bitRate = _bitRate;
+
+        copy->_gain = _gain;
+        copy->_drc = _drc;
     }
 
     return copy;
@@ -713,38 +538,34 @@ static NSMutableArray *masterBitRateArray = nil;
 
 - (void)encodeWithCoder:(NSCoder *)coder
 {
-    [coder encodeInt:2 forKey:@"HBAudioTrackVersion"];
+    [coder encodeInt:3 forKey:@"HBAudioTrackVersion"];
 
-    encodeObject(_track);
-    encodeObject(_codec);
-    encodeObject(_mixdown);
-    encodeObject(_sampleRate);
-    encodeObject(_bitRate);
-    encodeDouble(_drc);
-    encodeDouble(_gain);
+    encodeInteger(_sourceTrackIdx);
     encodeInt(_container);
 
-    encodeObject(_codecs);
-    encodeObject(_mixdowns);
-    encodeObject(_bitRates);
+    encodeInt(_encoder);
+    encodeInt(_mixdown);
+    encodeInt(_sampleRate);
+    encodeInt(_bitRate);
+
+    encodeDouble(_gain);
+    encodeDouble(_drc);
 }
 
 - (instancetype)initWithCoder:(NSCoder *)decoder
 {
     self = [super init];
 
-    decodeObject(_track, NSDictionary);
-    decodeObject(_codec, NSDictionary);
-    decodeObject(_mixdown, NSDictionary);
-    decodeObject(_sampleRate, NSDictionary);
-    decodeObject(_bitRate, NSDictionary);
-    decodeDouble(_drc);
-    decodeDouble(_gain);
+    decodeInteger(_sourceTrackIdx);
     decodeInt(_container);
 
-    decodeObject(_codecs, NSMutableArray);
-    decodeObject(_mixdowns, NSMutableArray);
-    decodeObject(_bitRates, NSArray);
+    decodeInt(_encoder);
+    decodeInt(_mixdown);
+    decodeInt(_sampleRate);
+    decodeInt(_bitRate);
+
+    decodeDouble(_gain);
+    decodeDouble(_drc);
 
     return self;
 }
index 1acd14a20a95178a166be0b629a339216aeec9a9..7f3b4a8f4e1f04af2bc88afea998aeb6584bf41c 100644 (file)
@@ -42,19 +42,3 @@ NS_ASSUME_NONNULL_BEGIN
 @end
 
 NS_ASSUME_NONNULL_END
-
-/**
- *  A series of value trasformers to bridge the libhb enums
- *  to the textual rapresentations used in the interface.
- */
-@interface HBEncoderTransformer : NSValueTransformer
-@end
-
-@interface HBMixdownTransformer : NSValueTransformer
-@end
-
-@interface HBSampleRateTransformer : NSValueTransformer
-@end
-
-@interface HBIntegerTransformer : NSValueTransformer
-@end
\ No newline at end of file
index 254a83aaed1ca31f0ee37d543104c90edbed9cf9..0e2e66a4cb0f7c71dce3fdef7aa1e37dcc98758c 100644 (file)
@@ -10,8 +10,6 @@
 
 #define DEFAULT_SAMPLERATE 48000
 
-static void *HBAudioEncoderContex = &HBAudioEncoderContex;
-
 @interface HBAudioTrackPreset ()
 
 @property (nonatomic, readwrite) int container;
@@ -257,6 +255,8 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
 - (NSArray<NSString *> *)sampleRates
 {
     NSMutableArray<NSString *> *sampleRates = [[NSMutableArray alloc] init];
+    [sampleRates addObject:@"Auto"];
+
     for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL);
          audio_samplerate != NULL;
          audio_samplerate  = hb_audio_samplerate_get_next(audio_samplerate))
@@ -294,7 +294,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
 {
     NSSet *retval = nil;
 
-    // Tell KVO to reaload the *enabled keyPaths
+    // Tell KVO to reload the *enabled keyPaths
     // after a change to encoder.
     if ([key isEqualToString:@"bitrateEnabled"] ||
         [key isEqualToString:@"passThruDisabled"] ||
@@ -306,6 +306,10 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
     {
         retval = [NSSet setWithObjects:@"encoder", nil];
     }
+    else if ([key isEqualToString:@"sampleRates"])
+    {
+        retval = [NSSet setWithObjects:@"encoder", @"mixdown", nil];
+    }
     else if ([key isEqualToString:@"bitRates"])
     {
         retval = [NSSet setWithObjects:@"encoder", @"mixdown", @"sampleRate", nil];
@@ -388,136 +392,3 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex;
 }
 
 @end
-
-#pragma mark - Value Trasformers
-
-@implementation HBEncoderTransformer
-
-+ (Class)transformedValueClass
-{
-    return [NSString class];
-}
-
-- (id)transformedValue:(id)value
-{
-    const char *name = hb_audio_encoder_get_name([value intValue]);
-    if (name)
-    {
-        return @(name);
-    }
-    else
-    {
-        return nil;
-    }
-}
-
-+ (BOOL)allowsReverseTransformation
-{
-    return YES;
-}
-
-- (id)reverseTransformedValue:(id)value
-{
-    return @(hb_audio_encoder_get_from_name([value UTF8String]));
-}
-
-@end
-
-@implementation HBMixdownTransformer
-
-+ (Class)transformedValueClass
-{
-    return [NSString class];
-}
-
-- (id)transformedValue:(id)value
-{
-    const char *name = hb_mixdown_get_name([value intValue]);
-    if (name)
-    {
-        return @(name);
-    }
-    else
-    {
-        return nil;
-    }
-}
-
-+ (BOOL)allowsReverseTransformation
-{
-    return YES;
-}
-
-- (id)reverseTransformedValue:(id)value
-{
-    return @(hb_mixdown_get_from_name([value UTF8String]));
-}
-
-@end
-
-@implementation HBSampleRateTransformer
-
-+ (Class)transformedValueClass
-{
-    return [NSString class];
-}
-
-- (id)transformedValue:(id)value
-{
-    const char *name = hb_audio_samplerate_get_name([value intValue]);
-    if (name)
-    {
-        return @(name);
-    }
-    else
-    {
-        return nil;
-    }
-}
-
-+ (BOOL)allowsReverseTransformation
-{
-    return YES;
-}
-
-- (id)reverseTransformedValue:(id)value
-{
-    int sampleRate = hb_audio_samplerate_get_from_name([value UTF8String]);
-    if (sampleRate < 0)
-    {
-        sampleRate = 0;
-    }
-    return @(sampleRate);
-}
-
-@end
-
-@implementation HBIntegerTransformer
-
-+ (Class)transformedValueClass
-{
-    return [NSString class];
-}
-
-- (id)transformedValue:(id)value
-{
-    // treat -1 as a special invalid value
-    // e.g. passthru has no bitrate since we have no source
-    if ([value intValue] == -1)
-    {
-        return @"N/A";
-    }
-    return [value stringValue];
-}
-
-+ (BOOL)allowsReverseTransformation
-{
-    return YES;
-}
-
-- (id)reverseTransformedValue:(id)value
-{
-    return @([value intValue]);
-}
-
-@end
diff --git a/macosx/HBAudioTransformers.h b/macosx/HBAudioTransformers.h
new file mode 100644 (file)
index 0000000..eefadda
--- /dev/null
@@ -0,0 +1,25 @@
+//
+//  HBAudioTransformers.h
+//  HandBrake
+//
+//  Created by Damiano Galassi on 26/08/2016.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ *  A series of value trasformers to bridge the libhb enums
+ *  to the textual rapresentations used in the interface.
+ */
+@interface HBEncoderTransformer : NSValueTransformer
+@end
+
+@interface HBMixdownTransformer : NSValueTransformer
+@end
+
+@interface HBSampleRateTransformer : NSValueTransformer
+@end
+
+@interface HBIntegerTransformer : NSValueTransformer
+@end
diff --git a/macosx/HBAudioTransformers.m b/macosx/HBAudioTransformers.m
new file mode 100644 (file)
index 0000000..4a4adec
--- /dev/null
@@ -0,0 +1,143 @@
+//
+//  HBAudioTransformers.m
+//  HandBrake
+//
+//  Created by Damiano Galassi on 26/08/2016.
+//
+//
+
+#import "HBAudioTransformers.h"
+#include "hb.h"
+
+#pragma mark - Value Trasformers
+
+@implementation HBEncoderTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSString class];
+}
+
+- (id)transformedValue:(id)value
+{
+    const char *name = hb_audio_encoder_get_name([value intValue]);
+    if (name)
+    {
+        return @(name);
+    }
+    else
+    {
+        return nil;
+    }
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return YES;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+    return @(hb_audio_encoder_get_from_name([value UTF8String]));
+}
+
+@end
+
+@implementation HBMixdownTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSString class];
+}
+
+- (id)transformedValue:(id)value
+{
+    const char *name = hb_mixdown_get_name([value intValue]);
+    if (name)
+    {
+        return @(name);
+    }
+    else
+    {
+        return nil;
+    }
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return YES;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+    return @(hb_mixdown_get_from_name([value UTF8String]));
+}
+
+@end
+
+@implementation HBSampleRateTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSString class];
+}
+
+- (id)transformedValue:(id)value
+{
+    const char *name = hb_audio_samplerate_get_name([value intValue]);
+    if (name)
+    {
+        return @(name);
+    }
+    else
+    {
+        return nil;
+    }
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return YES;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+    int sampleRate = hb_audio_samplerate_get_from_name([value UTF8String]);
+    if (sampleRate < 0)
+    {
+        sampleRate = 0;
+    }
+    return @(sampleRate);
+}
+
+@end
+
+@implementation HBIntegerTransformer
+
++ (Class)transformedValueClass
+{
+    return [NSString class];
+}
+
+- (id)transformedValue:(id)value
+{
+    // treat -1 as a special invalid value
+    // e.g. passthru has no bitrate since we have no source
+    if ([value intValue] == -1)
+    {
+        return @"N/A";
+    }
+    return [value stringValue];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+    return YES;
+}
+
+- (id)reverseTransformedValue:(id)value
+{
+    return @([value intValue]);
+}
+
+@end
index d26e2cea081dbe9ad42461d760586d602c8fe9d4..e90ccfd6c960a3816c5a167612fa890463462b57 100644 (file)
     // Now lets add our new tracks to the audio list here
     for (HBAudioTrack *audioTrack in self.audio.tracks)
     {
-        if (audioTrack.enabled)
+        if (audioTrack.isEnabled)
         {
             hb_audio_config_t *audio = (hb_audio_config_t *)calloc(1, sizeof(*audio));
             hb_audio_config_init(audio);
 
-            NSNumber *sampleRateToUse = ([audioTrack.sampleRate[keyAudioSamplerate] intValue] == 0 ?
-                                         audioTrack.track[keyAudioInputSampleRate] :
-                                         audioTrack.sampleRate[keyAudioSamplerate]);
+            NSDictionary *inputTrack = self.audio.sourceTracks[audioTrack.sourceTrackIdx];
 
-            audio->in.track            = [audioTrack.track[keyAudioTrackIndex] intValue] -1;
+            int sampleRateToUse = (audioTrack.sampleRate == 0 ?
+                                   [inputTrack[keyAudioInputSampleRate] intValue] :
+                                   audioTrack.sampleRate);
+
+            audio->in.track = (int)audioTrack.sourceTrackIdx - 1;
 
             // We go ahead and assign values to our audio->out.<properties>
             audio->out.track                     = audio->in.track;
-            audio->out.codec                     = [audioTrack.codec[keyAudioCodec] intValue];
+            audio->out.codec                     = audioTrack.encoder;
             audio->out.compression_level         = hb_audio_compression_get_default(audio->out.codec);
-            audio->out.mixdown                   = [audioTrack.mixdown[keyAudioMixdown] intValue];
+            audio->out.mixdown                   = audioTrack.mixdown;
             audio->out.normalize_mix_level       = 0;
-            audio->out.bitrate                   = [audioTrack.bitRate[keyAudioBitrate] intValue];
-            audio->out.samplerate                = [sampleRateToUse intValue];
+            audio->out.bitrate                   = audioTrack.bitRate;
+            audio->out.samplerate                = sampleRateToUse;
             audio->out.dither_method             = hb_audio_dither_get_default();
 
             // output is not passthru so apply gain
-            if (!([[audioTrack codec][keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG))
+            if (!(audioTrack.encoder & HB_ACODEC_PASS_FLAG))
             {
                 audio->out.gain = audioTrack.gain;
             }
                 audio->out.gain = 0;
             }
 
-            if (hb_audio_can_apply_drc([audioTrack.track[keyAudioInputCodec] intValue],
-                                       [audioTrack.track[keyAudioInputCodecParam] intValue],
-                                       [audioTrack.codec[keyAudioCodec] intValue]))
+            if (hb_audio_can_apply_drc([inputTrack[keyAudioInputCodec] intValue],
+                                       [inputTrack[keyAudioInputCodecParam] intValue],
+                                       audioTrack.encoder))
             {
                 audio->out.dynamic_range_compression = audioTrack.drc;
             }
index 829f4730048b23905a52e248e72bf3184d78b255..865cad7d8dafc1e25e636e1700af151dc70e31a8 100644 (file)
@@ -190,23 +190,25 @@ static NSDictionary            *shortHeightAttr;
 
         for (HBAudioTrack *audioTrack in self.audio.tracks)
         {
-            if (audioTrack.enabled)
+            if (audioTrack.isEnabled)
             {
-                audioCodecSummary = [NSString stringWithFormat: @"%@", audioTrack.codec[keyAudioCodecName]];
-                NSNumber *drc = @(audioTrack.drc);
-                NSNumber *gain = @(audioTrack.gain);
-                NSString *detailString = [NSString stringWithFormat: @"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps), DRC: %@, Gain: %@",
-                                          audioTrack.track[keyAudioTrackName],
-                                          audioTrack.codec[keyAudioCodecName],
-                                          audioTrack.mixdown[keyAudioMixdownName],
-                                          audioTrack.sampleRate[keyAudioSampleRateName],
-                                          audioTrack.bitRate[keyAudioBitrateName],
-                                          (0.0 < [drc floatValue]) ? (NSObject *)drc : (NSObject *)@"Off",
-                                          (0.0 != [gain floatValue]) ? (NSObject *)gain : (NSObject *)@"Off"
+                const char *codecName = hb_audio_encoder_get_name(audioTrack.encoder);
+                const char *mixdownName = hb_mixdown_get_name(audioTrack.mixdown);
+                const char *sampleRateName = audioTrack.sampleRate ? hb_audio_samplerate_get_name(audioTrack.sampleRate) : "Auto";
+
+                audioCodecSummary = [NSString stringWithFormat: @"%@", @(codecName)];
+                NSString *detailString = [NSString stringWithFormat: @"%@ Encoder: %@, Mixdown: %@, SampleRate: %@ khz, Bitrate: %d kbps, DRC: %@, Gain: %@",
+                                          self.audio.sourceTracks[audioTrack.sourceTrackIdx][keyAudioTrackName],
+                                          @(codecName),
+                                          @(mixdownName),
+                                          @(sampleRateName),
+                                          audioTrack.bitRate,
+                                          (0.0 < audioTrack.drc) ? @(audioTrack.drc) : NSLocalizedString(@"Off", nil),
+                                          (0.0 != audioTrack.gain) ? @(audioTrack.gain) : NSLocalizedString(@"Off", nil)
                                           ];
                 [audioDetails addObject: detailString];
                 // check if we have an Auto Passthru output track
-                if ([audioTrack.codec[keyAudioCodecName] isEqualToString: @"Auto Passthru"])
+                if ([@(codecName) isEqualToString: @"Auto Passthru"])
                 {
                     autoPassthruPresent = YES;
                 }
@@ -459,32 +461,28 @@ static NSDictionary            *shortHeightAttr;
         }
         
         // Ninth Line Subtitle Details
-        int i = 0;
         for (HBSubtitlesTrack *track in self.subtitles.tracks)
         {
             // Ignore the none track.
-            if (i == self.subtitles.tracks.count - 1)
+            if (track.isEnabled)
             {
-                continue;
-            }
-            
-            /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/
-            [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr];
-            [finalString appendString: self.subtitles.sourceTracks[track.sourceTrackIdx][@"keySubTrackName"] withAttributes:detailAttr];
-            if (track.forcedOnly)
-            {
-                [finalString appendString: @" - Forced Only" withAttributes:detailAttr];
-            }
-            if (track.burnedIn)
-            {
-                [finalString appendString: @" - Burned In" withAttributes:detailAttr];
-            }
-            if (track.def)
-            {
-                [finalString appendString: @" - Default" withAttributes:detailAttr];
+                // remember that index 0 of Subtitles can contain "Foreign Audio Search
+                [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr];
+                [finalString appendString: self.subtitles.sourceTracks[track.sourceTrackIdx][@"keySubTrackName"] withAttributes:detailAttr];
+                if (track.forcedOnly)
+                {
+                    [finalString appendString: @" - Forced Only" withAttributes:detailAttr];
+                }
+                if (track.burnedIn)
+                {
+                    [finalString appendString: @" - Burned In" withAttributes:detailAttr];
+                }
+                if (track.def)
+                {
+                    [finalString appendString: @" - Default" withAttributes:detailAttr];
+                }
+                [finalString appendString:@"\n" withAttributes:detailAttr];
             }
-            [finalString appendString:@"\n" withAttributes:detailAttr];
-            i++;
         }
     }
 
index 0964e5b73a810b8547fb6894c7b434a1f4693504..c6fd4ce65fe7de981f06fa82699808d1dca1794e 100644 (file)
                A91CE2FC1C7DB99D0068F46F /* HBPreset.h in Headers */ = {isa = PBXBuildFile; fileRef = A9CF25F21990D64E0023F727 /* HBPreset.h */; settings = {ATTRIBUTES = (Public, ); }; };
                A91CE2FD1C7DB99D0068F46F /* HBMutablePreset.h in Headers */ = {isa = PBXBuildFile; fileRef = A96CD1741BCC5F9100F372F1 /* HBMutablePreset.h */; settings = {ATTRIBUTES = (Public, ); }; };
                A91CE2FE1C7DB99D0068F46F /* HBTreeNode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D488A31996270300E9B1BA /* HBTreeNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               A91F97351D7B2A4E00D82DCE /* HBAudioTransformers.h in Headers */ = {isa = PBXBuildFile; fileRef = A91F97331D7B2A4E00D82DCE /* HBAudioTransformers.h */; };
+               A91F97361D7B2A4E00D82DCE /* HBAudioTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = A91F97341D7B2A4E00D82DCE /* HBAudioTransformers.m */; };
                A92268781A6E555500A8D5C5 /* HBAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A92268771A6E555500A8D5C5 /* HBAppDelegate.m */; };
                A922687B1A6E569B00A8D5C5 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = A92268791A6E569B00A8D5C5 /* MainWindow.xib */; };
                A932E26C1988334B0047D13E /* AudioDefaults.xib in Resources */ = {isa = PBXBuildFile; fileRef = A932E26A1988334B0047D13E /* AudioDefaults.xib */; };
                A91CE2CF1C7DABCE0068F46F /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };
                A91CE2D11C7DABDA0068F46F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
                A91CE2D31C7DABE40068F46F /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
+               A91F97331D7B2A4E00D82DCE /* HBAudioTransformers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAudioTransformers.h; sourceTree = "<group>"; };
+               A91F97341D7B2A4E00D82DCE /* HBAudioTransformers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudioTransformers.m; sourceTree = "<group>"; };
                A92268761A6E555500A8D5C5 /* HBAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAppDelegate.h; sourceTree = "<group>"; };
                A92268771A6E555500A8D5C5 /* HBAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAppDelegate.m; sourceTree = "<group>"; };
                A922687A1A6E569B00A8D5C5 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = MainWindow.xib; sourceTree = "<group>"; };
                                A932E272198834130047D13E /* HBAudioDefaults.m */,
                                A90A0CAD1988D57200DA65CE /* HBAudioTrackPreset.h */,
                                A90A0CAE1988D57200DA65CE /* HBAudioTrackPreset.m */,
+                               A91F97331D7B2A4E00D82DCE /* HBAudioTransformers.h */,
+                               A91F97341D7B2A4E00D82DCE /* HBAudioTransformers.m */,
                        );
                        name = Audio;
                        sourceTree = "<group>";
                                A91CE2FC1C7DB99D0068F46F /* HBPreset.h in Headers */,
                                A91CE2FD1C7DB99D0068F46F /* HBMutablePreset.h in Headers */,
                                A98B8E241C7DD2A200B810C9 /* HBPresetCoding.h in Headers */,
+                               A91F97351D7B2A4E00D82DCE /* HBAudioTransformers.h in Headers */,
                                A91CE2FE1C7DB99D0068F46F /* HBTreeNode.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                A91CE27F1C7DA7320068F46F /* HBTitle.m in Sources */,
                                A91CE2821C7DA7320068F46F /* HBJob.m in Sources */,
                                A91CE2841C7DA7320068F46F /* HBJob+HBJobConversion.m in Sources */,
+                               A91F97361D7B2A4E00D82DCE /* HBAudioTransformers.m in Sources */,
                                A91CE2861C7DA7320068F46F /* HBRange.m in Sources */,
                                A91CE2881C7DA7320068F46F /* HBVideo.m in Sources */,
                                A91CE28A1C7DA7320068F46F /* HBPicture.m in Sources */,