]> git.sesse.net Git - vlc/blob - modules/gui/macosx/AudioEffects.m
macosx/CAS: add MKV to the black list for HTTP streaming
[vlc] / modules / gui / macosx / AudioEffects.m
1 /*****************************************************************************
2  * AudioEffects.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2004-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *          Jérôme Decoodt <djc@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # import "config.h"
27 #endif
28
29 #import "intf.h"
30 #import "AudioEffects.h"
31 #import "../../audio_filter/equalizer_presets.h"
32 #import "CompatibilityFixes.h"
33 #import "SharedDialogs.h"
34
35 #import <vlc_common.h>
36 #import <vlc_strings.h>
37
38 #import <math.h>
39
40 @interface VLCAudioEffects (Internal)
41 - (void)resetProfileSelector;
42 - (void)updatePresetSelector;
43 - (void)setBandSliderValuesForPreset:(NSInteger)presetID;
44 @end
45
46 #pragma mark -
47 #pragma mark Initialization
48
49 @implementation VLCAudioEffects
50 static VLCAudioEffects *_o_sharedInstance = nil;
51
52 + (VLCAudioEffects *)sharedInstance
53 {
54     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
55 }
56
57 + (void)initialize{
58     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
59
60     NSString * workString;
61     NSMutableArray * workValues = [[NSMutableArray alloc] initWithCapacity:NB_PRESETS];
62     NSMutableArray * workPreamp = [[NSMutableArray alloc] initWithCapacity:NB_PRESETS];
63     NSMutableArray * workTitles = [[NSMutableArray alloc] initWithCapacity:NB_PRESETS];
64     NSMutableArray * workNames = [[NSMutableArray alloc] initWithCapacity:NB_PRESETS];
65
66     for (int i = 0 ; i < NB_PRESETS ; i++) {
67         workString = [NSString stringWithFormat:@"%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f",
68                       eqz_preset_10b[i].f_amp[0],
69                       eqz_preset_10b[i].f_amp[1],
70                       eqz_preset_10b[i].f_amp[2],
71                       eqz_preset_10b[i].f_amp[3],
72                       eqz_preset_10b[i].f_amp[4],
73                       eqz_preset_10b[i].f_amp[5],
74                       eqz_preset_10b[i].f_amp[6],
75                       eqz_preset_10b[i].f_amp[7],
76                       eqz_preset_10b[i].f_amp[8],
77                       eqz_preset_10b[i].f_amp[9]];
78         [workValues addObject:workString];
79         [workPreamp addObject:[NSString stringWithFormat:@"%1.f", eqz_preset_10b[i].f_preamp]];
80         [workTitles addObject:[NSString stringWithUTF8String:preset_list_text[i]]];
81         [workNames addObject:[NSString stringWithUTF8String:preset_list[i]]];
82     }
83
84     NSString *defaultProfile = [NSString stringWithFormat:@"ZmxhdA==;;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%i",
85                             .0,25.,100.,-11.,8.,2.5,7.,.85,1.,.4,.5,.5,2.,0];
86
87     NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithArray:workValues], @"EQValues", [NSArray arrayWithArray:workPreamp], @"EQPreampValues", [NSArray arrayWithArray:workTitles], @"EQTitles", [NSArray arrayWithArray:workNames], @"EQNames", [NSArray arrayWithObject:defaultProfile], @"AudioEffectProfiles", [NSArray arrayWithObject:_NS("Default")], @"AudioEffectProfileNames", nil];
88     [defaults registerDefaults:appDefaults];
89
90     [workValues release];
91     [workPreamp release];
92     [workTitles release];
93     [workNames release];
94 }
95
96 - (id)init
97 {
98     if (_o_sharedInstance)
99         [self dealloc];
100     else {
101         p_intf = VLCIntf;
102         _o_sharedInstance = [super init];
103     }
104
105     return _o_sharedInstance;
106 }
107
108 - (void)awakeFromNib
109 {
110     /* setup the user's language */
111     /* Equalizer */
112     [o_eq_enable_ckb setTitle:_NS("Enable")];
113     [o_eq_twopass_ckb setTitle:_NS("2 Pass")];
114     [o_eq_preamp_lbl setStringValue:_NS("Preamp")];
115
116     /* Compressor */
117     [o_comp_enable_ckb setTitle:_NS("Enable dynamic range compressor")];
118     [o_comp_reset_btn setTitle:_NS("Reset")];
119     [o_comp_band1_lbl setStringValue:_NS("RMS/peak")];;
120     [o_comp_band2_lbl setStringValue:_NS("Attack")];
121     [o_comp_band3_lbl setStringValue:_NS("Release")];
122     [o_comp_band4_lbl setStringValue:_NS("Threshold")];
123     [o_comp_band5_lbl setStringValue:_NS("Ratio")];
124     [o_comp_band6_lbl setStringValue:_NS("Knee radius")];
125     [o_comp_band7_lbl setStringValue:_NS("Makeup gain")];
126
127     /* Spatializer */
128     [o_spat_enable_ckb setTitle:_NS("Enable Spatializer")];
129     [o_spat_reset_btn setTitle:_NS("Reset")];
130     [o_spat_band1_lbl setStringValue:_NS("Size")];
131     [o_spat_band2_lbl setStringValue:_NS("Width")];
132     [o_spat_band3_lbl setStringValue:_NS("Wet")];
133     [o_spat_band4_lbl setStringValue:_NS("Dry")];
134     [o_spat_band5_lbl setStringValue:_NS("Damp")];
135
136     /* Filter */
137     [o_filter_headPhone_ckb setTitle:_NS("Headphone virtualization")];
138     [o_filter_normLevel_ckb setTitle:_NS("Volume normalization")];
139     [o_filter_normLevel_lbl setStringValue:_NS("Maximum level")];
140     [o_filter_karaoke_ckb setTitle:_NS("Karaoke")];
141
142     /* generic */
143     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"equalizer"]] setLabel:_NS("Equalizer")];
144     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"compressor"]] setLabel:_NS("Compressor")];
145     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"spatializer"]] setLabel:_NS("Spatializer")];
146     [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"filter"]] setLabel:_NS("Filter")];
147     [o_window setTitle:_NS("Audio Effects")];
148     [o_window setExcludedFromWindowsMenu:YES];
149     if (!OSX_SNOW_LEOPARD)
150         [o_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
151
152     [self setupEqualizer];
153     [self resetCompressor];
154     [self resetSpatializer];
155     [self resetAudioFilters];
156     [self resetProfileSelector];
157 }
158
159 #pragma mark -
160 #pragma mark internal functions
161
162 - (void)setAudioFilter: (char *)psz_name on:(BOOL)b_on
163 {
164     char *psz_tmp;
165     audio_output_t * p_aout = getAout();
166     if (p_aout)
167         psz_tmp = var_GetNonEmptyString(p_aout, "audio-filter");
168     else
169         psz_tmp = config_GetPsz(p_intf, "audio-filter");
170
171     if (b_on) {
172         if (!psz_tmp)
173             config_PutPsz(p_intf, "audio-filter", psz_name);
174         else if ((NSInteger)strstr(psz_tmp, psz_name) == NO) {
175             psz_tmp = (char *)[[NSString stringWithFormat: @"%s:%s", psz_tmp, psz_name] UTF8String];
176             config_PutPsz(p_intf, "audio-filter", psz_tmp);
177         }
178     } else {
179         if (psz_tmp) {
180             psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@":%s",psz_name]]] UTF8String];
181             psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@"%s:",psz_name]]] UTF8String];
182             psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithUTF8String:psz_name]]] UTF8String];
183             config_PutPsz(p_intf, "audio-filter", psz_tmp);
184         }
185     }
186
187     if (p_aout) {
188         playlist_EnableAudioFilter(pl_Get(p_intf), psz_name, b_on);
189         vlc_object_release(p_aout);
190     }
191 }
192
193 - (void)resetProfileSelector
194 {
195     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
196     [o_profile_pop removeAllItems];
197
198     NSArray * profileNames = [defaults objectForKey:@"AudioEffectProfileNames"];
199     [o_profile_pop addItemsWithTitles:profileNames];
200
201     [[o_profile_pop menu] addItem:[NSMenuItem separatorItem]];
202     [o_profile_pop addItemWithTitle:_NS("Save selection as new profile...")];
203     [[o_profile_pop lastItem] setTarget: self];
204     [[o_profile_pop lastItem] setAction: @selector(addAudioEffectsProfile:)];
205
206     if ([profileNames count] > 1) {
207         [o_profile_pop addItemWithTitle:_NS("Organize Profiles...")];
208         [[o_profile_pop lastItem] setTarget: self];
209         [[o_profile_pop lastItem] setAction: @selector(removeAudioEffectsProfile:)];
210     }
211
212     [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"AudioEffectSelectedProfile"]];
213     [self profileSelectorAction:self];
214 }
215
216 #pragma mark -
217 #pragma mark generic code
218 - (IBAction)toggleWindow:(id)sender
219 {
220     if ([o_window isVisible])
221         [o_window orderOut:sender];
222     else
223         [o_window makeKeyAndOrderFront:sender];
224 }
225
226 - (IBAction)profileSelectorAction:(id)sender
227 {
228     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
229     NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
230
231     audio_output_t * p_aout = getAout();
232     playlist_t * p_playlist = pl_Get(p_intf);
233
234     if (p_aout) {
235         /* disable existing filters */
236         playlist_EnableAudioFilter(p_playlist, "equalizer", false);
237         playlist_EnableAudioFilter(p_playlist, "compressor", false);
238         playlist_EnableAudioFilter(p_playlist, "spatializer", false);
239         playlist_EnableAudioFilter(p_playlist, "compressor", false);
240         playlist_EnableAudioFilter(p_playlist, "headphone", false);
241         playlist_EnableAudioFilter(p_playlist, "normvol", false);
242         playlist_EnableAudioFilter(p_playlist, "karaoke", false);
243     }
244
245     /* fetch preset */
246     NSArray *items = [[[defaults objectForKey:@"AudioEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
247
248     /* eq preset */
249     vlc_object_t *p_object = VLC_OBJECT(getAout());
250     if (p_object == NULL)
251         p_object = vlc_object_hold(pl_Get(p_intf));
252     var_SetString(p_object,"equalizer-preset",vlc_b64_decode([[items objectAtIndex:0] UTF8String]));
253     vlc_object_release(p_object);
254
255     /* filter handling */
256     NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
257     NSArray *tempArray;
258     NSUInteger count;
259     /* enable the new filters, if we have an aout */
260     if (p_aout) {
261         if ([tempString length] > 0) {
262             tempArray = [tempString componentsSeparatedByString:@":"];
263             count = [tempArray count];
264             for (NSUInteger x = 0; x < count; x++)
265                 playlist_EnableAudioFilter(p_playlist, (char *)[[tempArray objectAtIndex:x] UTF8String], true);
266         }
267     }
268     config_PutPsz(p_intf,"audio-filter",[tempString UTF8String]);
269
270     /* values */
271     config_PutFloat(p_intf, "compressor-rms-peak",[[items objectAtIndex:2] floatValue]);
272     config_PutFloat(p_intf, "compressor-attack",[[items objectAtIndex:3] floatValue]);
273     config_PutFloat(p_intf, "compressor-release",[[items objectAtIndex:4] floatValue]);
274     config_PutFloat(p_intf, "compressor-threshold",[[items objectAtIndex:5] floatValue]);
275     config_PutFloat(p_intf, "compressor-ratio",[[items objectAtIndex:6] floatValue]);
276     config_PutFloat(p_intf, "compressor-knee",[[items objectAtIndex:7] floatValue]);
277     config_PutFloat(p_intf, "compressor-makeup-gain",[[items objectAtIndex:8] floatValue]);
278     config_PutFloat(p_intf, "spatializer-roomsize",[[items objectAtIndex:9] floatValue]);
279     config_PutFloat(p_intf, "spatializer-width",[[items objectAtIndex:10] floatValue]);
280     config_PutFloat(p_intf, "spatializer-wet",[[items objectAtIndex:11] floatValue]);
281     config_PutFloat(p_intf, "spatializer-dry",[[items objectAtIndex:12] floatValue]);
282     config_PutFloat(p_intf, "spatializer-damp",[[items objectAtIndex:13] floatValue]);
283     config_PutFloat(p_intf, "norm-max-level",[[items objectAtIndex:14] floatValue]);
284     config_PutInt(p_intf, "equalizer-2pass",[[items objectAtIndex:15] intValue]);
285
286     /* set values on-the-fly if we have an aout */
287     if (p_aout) {
288         var_SetFloat(p_aout, "compressor-rms-peak", [[items objectAtIndex:2] floatValue]);
289         var_SetFloat(p_aout, "compressor-attack", [[items objectAtIndex:3] floatValue]);
290         var_SetFloat(p_aout, "compressor-release", [[items objectAtIndex:4] floatValue]);
291         var_SetFloat(p_aout, "compressor-threshold", [[items objectAtIndex:5] floatValue]);
292         var_SetFloat(p_aout, "compressor-ratio", [[items objectAtIndex:6] floatValue]);
293         var_SetFloat(p_aout, "compressor-knee", [[items objectAtIndex:7] floatValue]);
294         var_SetFloat(p_aout, "compressor-makeup-gain", [[items objectAtIndex:8] floatValue]);
295         var_SetFloat(p_aout, "spatializer-roomsize", [[items objectAtIndex:9] floatValue]);
296         var_SetFloat(p_aout, "spatializer-width", [[items objectAtIndex:10] floatValue]);
297         var_SetFloat(p_aout, "spatializer-wet", [[items objectAtIndex:11] floatValue]);
298         var_SetFloat(p_aout, "spatializer-dry", [[items objectAtIndex:12] floatValue]);
299         var_SetFloat(p_aout, "spatializer-damp", [[items objectAtIndex:13] floatValue]);
300         var_SetFloat(p_aout, "norm-max-level", [[items objectAtIndex:14] floatValue]);
301         var_SetBool(p_aout, "equalizer-2pass", (BOOL)[[items objectAtIndex:15] intValue]);
302     }
303
304     /* update UI */
305     if ([tempString rangeOfString:@"equalizer"].location == NSNotFound)
306         [o_eq_enable_ckb setState:NSOffState];
307     else
308         [o_eq_enable_ckb setState:NSOnState];
309     [o_eq_twopass_ckb setState:[[items objectAtIndex:15] intValue]];
310     [self resetCompressor];
311     [self resetSpatializer];
312     [self resetAudioFilters];
313     [self updatePresetSelector];
314
315     /* store current profile selection */
316     [defaults setInteger:selectedProfile forKey:@"AudioEffectSelectedProfile"];
317     [defaults synchronize];
318
319     if (p_aout)
320         vlc_object_release(p_aout);
321 }
322
323 - (IBAction)addAudioEffectsProfile:(id)sender
324 {
325     /* show panel */
326     VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
327     [panel setTitle: _NS("Save current selection as new profile")];
328     [panel setSubTitle: _NS("Enter a name for the new profile:")];
329     [panel setCancelButtonLabel: _NS("Cancel")];
330     [panel setOKButtonLabel: _NS("Save")];
331     [panel setTarget:self];
332     b_genericAudioProfileInInteraction = YES;
333
334     [panel runModalForWindow:o_window];
335 }
336
337 - (IBAction)removeAudioEffectsProfile:(id)sender
338 {
339     /* show panel */
340     VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
341     [panel setTitle:_NS("Remove a preset")];
342     [panel setSubTitle:_NS("Select the preset you would like to remove:")];
343     [panel setOKButtonLabel:_NS("Remove")];
344     [panel setCancelButtonLabel:_NS("Cancel")];
345     [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"AudioEffectProfileNames"]];
346     [panel setTarget:self];
347     b_genericAudioProfileInInteraction = YES;
348
349     [panel runModalForWindow:o_window];
350 }
351
352 #pragma mark -
353 #pragma mark Equalizer
354 static bool GetEqualizerStatus(intf_thread_t *p_custom_intf,
355                              char *psz_name)
356 {
357     char *psz_parser, *psz_string = NULL;
358     vlc_object_t *p_object = VLC_OBJECT(getAout());
359     if (p_object == NULL)
360         p_object = vlc_object_hold(pl_Get(p_custom_intf));
361
362     psz_string = config_GetPsz(p_custom_intf, "audio-filter");
363
364     if (!psz_string)
365         psz_string = var_GetNonEmptyString(p_object, "audio-filter");
366
367     vlc_object_release(p_object);
368
369     if (!psz_string)
370         return false;
371
372     psz_parser = strstr(psz_string, psz_name);
373
374     free(psz_string);
375
376     if (psz_parser)
377         return true;
378     else
379         return false;
380 }
381
382 - (void)setupEqualizer
383 {
384     vlc_object_t *p_object = VLC_OBJECT(getAout());
385     if (p_object == NULL)
386         p_object = vlc_object_hold(pl_Get(p_intf));
387
388     var_Create(p_object, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
389
390     NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
391     NSArray * presets = [defaults objectForKey:@"EQNames"];
392     NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
393     NSInteger currentPresetIndex = 0;
394     if ([currentPreset length] > 0) {
395         currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
396             return [obj isEqualToString:currentPreset];
397         }];
398     }
399
400     char psz_bands[100];
401     snprintf(psz_bands, sizeof(psz_bands),
402              "%.1f %.1f %.1f %.1f %.1f %.1f %.1f "
403              "%.1f %.1f %.1f",
404              eqz_preset_10b[currentPresetIndex].f_amp[0],
405              eqz_preset_10b[currentPresetIndex].f_amp[1],
406              eqz_preset_10b[currentPresetIndex].f_amp[2],
407              eqz_preset_10b[currentPresetIndex].f_amp[3],
408              eqz_preset_10b[currentPresetIndex].f_amp[4],
409              eqz_preset_10b[currentPresetIndex].f_amp[5],
410              eqz_preset_10b[currentPresetIndex].f_amp[6],
411              eqz_preset_10b[currentPresetIndex].f_amp[7],
412              eqz_preset_10b[currentPresetIndex].f_amp[8],
413              eqz_preset_10b[currentPresetIndex].f_amp[9]);
414
415     var_Create(p_object, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
416     var_Create(p_object, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
417     var_SetFloat(p_object, "equalizer-preamp", eqz_preset_10b[currentPresetIndex].f_preamp);
418     var_SetString(p_object, "equalizer-bands", psz_bands);
419     vlc_object_release(p_object);
420
421     [self updatePresetSelector];
422
423     [self equalizerUpdated];
424 }
425
426 - (void)updatePresetSelector
427 {
428     [o_eq_presets_popup removeAllItems];
429     [o_eq_presets_popup addItemsWithTitles:[[NSUserDefaults standardUserDefaults] objectForKey:@"EQTitles"]];
430     [[o_eq_presets_popup menu] addItem:[NSMenuItem separatorItem]];
431     [o_eq_presets_popup addItemWithTitle:_NS("Add new Preset...")];
432     [[o_eq_presets_popup lastItem] setTarget: self];
433     [[o_eq_presets_popup lastItem] setAction: @selector(addPresetAction:)];
434     [o_eq_presets_popup addItemWithTitle:_NS("Organize Presets...")];
435     [[o_eq_presets_popup lastItem] setTarget: self];
436     [[o_eq_presets_popup lastItem] setAction: @selector(deletePresetAction:)];
437
438     vlc_object_t *p_object = VLC_OBJECT(getAout());
439     if (p_object == NULL)
440         p_object = vlc_object_hold(pl_Get(p_intf));
441
442     NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
443     NSArray * presets = [defaults objectForKey:@"EQNames"];
444     NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
445     NSInteger currentPresetIndex = 0;
446     if ([currentPreset length] > 0) {
447         currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
448             return [obj isEqualToString:currentPreset];
449         }];
450     }
451
452     [o_eq_presets_popup selectItemAtIndex:currentPresetIndex];
453     [o_eq_preamp_sld setFloatValue:[[[defaults objectForKey:@"EQPreampValues"] objectAtIndex:currentPresetIndex] floatValue]];
454     [self setBandSliderValuesForPreset:currentPresetIndex];
455
456     vlc_object_release(p_object);
457 }
458
459 - (void)equalizerUpdated
460 {
461     float f_preamp, f_band[10];
462     char *psz_bands, *psz_bands_init, *p_next;
463     bool b_2p;
464     bool b_enabled = GetEqualizerStatus(p_intf, (char *)"equalizer");
465     vlc_object_t *p_object = VLC_OBJECT(getAout());
466
467     if (p_object == NULL)
468         p_object = vlc_object_hold(pl_Get(p_intf));
469
470     var_Create(p_object, "equalizer-preamp", VLC_VAR_FLOAT |
471                VLC_VAR_DOINHERIT);
472     var_Create(p_object, "equalizer-bands", VLC_VAR_STRING |
473                VLC_VAR_DOINHERIT);
474
475     psz_bands = var_GetNonEmptyString(p_object, "equalizer-bands");
476
477     if (psz_bands == NULL)
478         psz_bands = strdup("0 0 0 0 0 0 0 0 0 0");
479
480     b_2p = (BOOL)config_GetInt(p_object, "equalizer-2pass");
481     f_preamp = config_GetFloat(p_object, "equalizer-preamp");
482
483     vlc_object_release(p_object);
484
485     /* Setup sliders */
486     [self updatePresetSelector];
487
488     /* Set the the checkboxes */
489     [o_eq_enable_ckb setState: b_enabled];
490     [o_eq_twopass_ckb setState: b_2p];
491 }
492
493 - (id)sliderByIndex:(int)index
494 {
495     switch(index) {
496         case 0 : return o_eq_band1_sld;
497         case 1 : return o_eq_band2_sld;
498         case 2 : return o_eq_band3_sld;
499         case 3 : return o_eq_band4_sld;
500         case 4 : return o_eq_band5_sld;
501         case 5 : return o_eq_band6_sld;
502         case 6 : return o_eq_band7_sld;
503         case 7 : return o_eq_band8_sld;
504         case 8 : return o_eq_band9_sld;
505         case 9 : return o_eq_band10_sld;
506         default : return nil;
507     }
508 }
509
510 - (void)setBandSlidersValues:(float *)values
511 {
512     for (int i = 0 ; i<= 9 ; i++)
513         [self setValue:values[i] forSlider:i];
514 }
515
516 - (void)setBandSliderValuesForPreset:(NSInteger)presetID
517 {
518     NSString * preset = [[[NSUserDefaults standardUserDefaults] objectForKey:@"EQValues"] objectAtIndex:presetID];
519     NSArray * values = [preset componentsSeparatedByString:@" "];
520     NSUInteger count = [values count];
521     for (NSUInteger x = 0; x < count; x++)
522         [self setValue:[[values objectAtIndex:x] floatValue] forSlider:x];
523 }
524
525 - (void)initBandSliders
526 {
527     for (int i = 0 ; i< 9 ; i++)
528         [self setValue:0.0 forSlider:i];
529 }
530
531 - (NSString *)generatePresetString
532 {
533     return [NSString stringWithFormat:@"%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f",
534             [o_eq_band1_sld floatValue],
535             [o_eq_band2_sld floatValue],
536             [o_eq_band3_sld floatValue],
537             [o_eq_band4_sld floatValue],
538             [o_eq_band5_sld floatValue],
539             [o_eq_band6_sld floatValue],
540             [o_eq_band7_sld floatValue],
541             [o_eq_band8_sld floatValue],
542             [o_eq_band9_sld floatValue],
543             [o_eq_band10_sld floatValue]];
544 }
545
546 - (void)setValue:(float)value forSlider:(int)index
547 {
548     id slider = [self sliderByIndex:index];
549
550     if (slider != nil)
551         [slider setFloatValue:value];
552 }
553
554 - (IBAction)eq_enable:(id)sender
555 {
556     [self setAudioFilter: "equalizer" on:[sender state]];
557 }
558
559 - (IBAction)eq_bandSliderUpdated:(id)sender
560 {
561     vlc_object_t *p_object = VLC_OBJECT(getAout());
562
563     if (p_object == NULL)
564         p_object = vlc_object_hold(pl_Get(p_intf));
565
566     var_SetString(p_object, "equalizer-bands", [[self generatePresetString] UTF8String]);
567
568     /* save changed to config */
569     config_PutPsz(p_intf, "equalizer-bands", [[self generatePresetString] UTF8String]);
570
571     vlc_object_release(p_object);
572 }
573
574 - (IBAction)eq_changePreset:(id)sender
575 {
576     vlc_object_t *p_object= VLC_OBJECT(getAout());
577     if (p_object == NULL)
578         p_object = vlc_object_hold(pl_Get(p_intf));
579     NSInteger numberOfChosenPreset = [sender indexOfSelectedItem];
580     NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
581
582     NSString *preset = [[defaults objectForKey:@"EQValues"] objectAtIndex:numberOfChosenPreset];
583     NSString *preamp = [[defaults objectForKey:@"EQPreampValues"] objectAtIndex:numberOfChosenPreset];
584
585     var_SetString(p_object, "equalizer-bands", [preset UTF8String]);
586     var_SetFloat(p_object, "equalizer-preamp", [preamp floatValue]);
587     var_SetString(p_object , "equalizer-preset" , [[[defaults objectForKey:@"EQNames"] objectAtIndex:numberOfChosenPreset] UTF8String]);
588
589     [o_eq_preamp_sld setFloatValue: [preamp floatValue]];
590     [self setBandSliderValuesForPreset:numberOfChosenPreset];
591
592     /* save changed to config */
593     config_PutPsz(p_intf, "equalizer-bands", [preset UTF8String]);
594     config_PutFloat(p_intf, "equalizer-preamp", [preamp floatValue]);
595     config_PutPsz(p_intf, "equalizer-preset", [[[defaults objectForKey:@"EQNames"] objectAtIndex:numberOfChosenPreset] UTF8String]);
596
597     vlc_object_release(p_object);
598 }
599
600 - (IBAction)eq_preampSliderUpdated:(id)sender
601 {
602     float f_preamp = [sender floatValue] ;
603
604     vlc_object_t *p_object = VLC_OBJECT(getAout());
605     if (p_object == NULL)
606         p_object = vlc_object_hold(pl_Get(p_intf));
607
608     var_SetFloat(p_object, "equalizer-preamp", f_preamp);
609
610     /* save changed to config */
611     config_PutFloat(p_intf, "equalizer-preamp", f_preamp);
612
613     vlc_object_release(p_object);
614 }
615 - (IBAction)eq_twopass:(id)sender
616 {
617     bool b_2p = [sender state] ? true : false;
618     audio_output_t *p_aout = getAout();
619     vlc_object_t *p_object= VLC_OBJECT(p_aout);
620     if (p_object == NULL)
621         p_object = vlc_object_hold(pl_Get(p_intf));
622
623     var_SetBool(p_object, "equalizer-2pass", b_2p);
624
625     /* save changed to config */
626     config_PutInt(p_intf, "equalizer-2pass", (int)b_2p);
627
628     vlc_object_release(p_object);
629 }
630
631 - (IBAction)addPresetAction:(id)sender
632 {
633     /* show panel */
634     VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
635     [panel setTitle: _NS("Save current selection as new preset")];
636     [panel setSubTitle: _NS("Enter a name for the new preset:")];
637     [panel setCancelButtonLabel: _NS("Cancel")];
638     [panel setOKButtonLabel: _NS("Save")];
639     [panel setTarget:self];
640     b_genericAudioProfileInInteraction = NO;
641
642     [panel runModalForWindow:o_window];
643 }
644
645 - (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
646 {
647     if (value == NSOKButton) {
648         if ([text length] > 0) {
649             NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
650
651             if (!b_genericAudioProfileInInteraction) {
652
653                 NSMutableArray * workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQValues"]];
654                 [workArray addObject:[self generatePresetString]];
655                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQValues"];
656                 [workArray release];
657                 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
658                 [workArray addObject:text];
659                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
660                 [workArray release];
661                 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQPreampValues"]];
662                 [workArray addObject:[NSString stringWithFormat:@"%.1f", [o_eq_preamp_sld floatValue]]];
663                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQPreampValues"];
664                 [workArray release];
665                 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
666                 [workArray addObject:[text decomposedStringWithCanonicalMapping]];
667                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
668                 [workArray release];
669                 [defaults synchronize];
670
671                 /* update VLC internals */
672                 vlc_object_t *p_object= VLC_OBJECT(getAout());
673                 if (p_object == NULL)
674                     p_object = vlc_object_hold(pl_Get(p_intf));
675
676                 var_SetString(p_object , "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
677                 config_PutPsz(p_object, "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
678
679                 vlc_object_release(p_object);
680
681                 /* update UI */
682                 [self updatePresetSelector];
683             } else {
684                 vlc_object_t *p_object = VLC_OBJECT(getAout());
685                 if (p_object == NULL)
686                     p_object = vlc_object_hold(pl_Get(p_intf));
687
688                 NSArray * presets = [defaults objectForKey:@"EQNames"];
689                 NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
690                 NSInteger currentPresetIndex = 0;
691                 if ([currentPreset length] > 0) {
692                     currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
693                         return [obj isEqualToString:currentPreset];
694                     }];
695                 }
696                 NSString *newProfile = [NSString stringWithFormat:@"%s;%s;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%lli",
697                                         vlc_b64_encode(var_GetNonEmptyString(p_object, "equalizer-preset")),
698                                         vlc_b64_encode(config_GetPsz(p_intf, "audio-filter")),
699                                         config_GetFloat(p_intf, "compressor-rms-peak"),
700                                         config_GetFloat(p_intf, "compressor-attack"),
701                                         config_GetFloat(p_intf, "compressor-release"),
702                                         config_GetFloat(p_intf, "compressor-threshold"),
703                                         config_GetFloat(p_intf, "compressor-ratio"),
704                                         config_GetFloat(p_intf, "compressor-knee"),
705                                         config_GetFloat(p_intf, "compressor-makeup-gain"),
706                                         config_GetFloat(p_intf, "spatializer-roomsize"),
707                                         config_GetFloat(p_intf, "spatializer-width"),
708                                         config_GetFloat(p_intf, "spatializer-wet"),
709                                         config_GetFloat(p_intf, "spatializer-dry"),
710                                         config_GetFloat(p_intf, "spatializer-damp"),
711                                         config_GetFloat(p_intf, "norm-max-level"),
712                                         config_GetInt(p_intf,"equalizer-2pass")];
713
714                 /* add string to user defaults as well as a label */
715                 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
716                 NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfiles"]];
717                 [workArray addObject:newProfile];
718                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfiles"];
719                 [defaults setInteger:[workArray count] - 1 forKey:@"AudioEffectSelectedProfile"];
720                 [workArray release];
721                 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
722                 [workArray addObject:text];
723                 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
724                 [workArray release];
725
726                 /* save defaults */
727                 [defaults synchronize];
728                 vlc_object_release(p_object);
729             }
730         }
731     }
732
733     [self resetProfileSelector];
734 }
735
736 - (IBAction)deletePresetAction:(id)sender
737 {
738     VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
739     [panel setTitle:_NS("Remove a preset")];
740     [panel setSubTitle:_NS("Select the preset you would like to remove:")];
741     [panel setOKButtonLabel:_NS("Remove")];
742     [panel setCancelButtonLabel:_NS("Cancel")];
743     [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"EQTitles"]];
744     [panel setTarget:self];
745     b_genericAudioProfileInInteraction = NO;
746
747     [panel runModalForWindow:o_window];
748 }
749
750 - (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
751 {
752     if (value == NSOKButton) {
753         if (!b_genericAudioProfileInInteraction) {
754             /* remove requested profile from the arrays */
755             NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
756             NSMutableArray * workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQValues"]];
757             [workArray removeObjectAtIndex:item];
758             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQValues"];
759             [workArray release];
760             workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
761             [workArray removeObjectAtIndex:item];
762             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
763             [workArray release];
764             workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQPreampValues"]];
765             [workArray removeObjectAtIndex:item];
766             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQPreampValues"];
767             [workArray release];
768             workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
769             [workArray removeObjectAtIndex:item];
770             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
771             [workArray release];
772             [defaults synchronize];
773
774             /* update UI */
775             [self updatePresetSelector];
776         } else {
777             /* remove selected profile from settings */
778             NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
779             NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfiles"]];
780             [workArray removeObjectAtIndex:item];
781             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfiles"];
782             [workArray release];
783             workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
784             [workArray removeObjectAtIndex:item];
785             [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
786             [workArray release];
787
788             /* save defaults */
789             [defaults synchronize];
790             [self resetProfileSelector];
791         }
792     }
793 }
794
795 #pragma mark -
796 #pragma mark Compressor
797 - (void)resetCompressor
798 {
799     char * psz_afilters;
800     psz_afilters = config_GetPsz(p_intf, "audio-filter");
801     if (psz_afilters) {
802         [o_comp_enable_ckb setState: (NSInteger)strstr(psz_afilters, "compressor") ];
803         free(psz_afilters);
804     }
805     else
806         [o_comp_enable_ckb setState: NSOffState];
807
808     [o_comp_band1_sld setFloatValue: config_GetFloat(p_intf, "compressor-rms-peak")];
809     [o_comp_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [o_comp_band1_sld floatValue]]];
810     [o_comp_band2_sld setFloatValue: config_GetFloat(p_intf, "compressor-attack")];
811     [o_comp_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f ms", [o_comp_band2_sld floatValue]]];
812     [o_comp_band3_sld setFloatValue: config_GetFloat(p_intf, "compressor-release")];
813     [o_comp_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%3.1f ms", [o_comp_band3_sld floatValue]]];
814     [o_comp_band4_sld setFloatValue: config_GetFloat(p_intf, "compressor-threshold")];
815     [o_comp_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f dB", [o_comp_band4_sld floatValue]]];
816     [o_comp_band5_sld setFloatValue: config_GetFloat(p_intf, "compressor-ratio")];
817     [o_comp_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f:1", [o_comp_band5_sld floatValue]]];
818     [o_comp_band6_sld setFloatValue: config_GetFloat(p_intf, "compressor-knee")];
819     [o_comp_band6_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [o_comp_band6_sld floatValue]]];
820     [o_comp_band7_sld setFloatValue: config_GetFloat(p_intf, "compressor-makeup-gain")];
821     [o_comp_band7_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [o_comp_band7_sld floatValue]]];
822 }
823
824 - (IBAction)resetCompressorValues:(id)sender
825 {
826     config_PutFloat(p_intf, "compressor-rms-peak", 0.000000);
827     config_PutFloat(p_intf, "compressor-attack", 25.000000);
828     config_PutFloat(p_intf, "compressor-release", 100.000000);
829     config_PutFloat(p_intf, "compressor-threshold", -11.000000);
830     config_PutFloat(p_intf, "compressor-ratio", 8.000000);
831     config_PutFloat(p_intf, "compressor-knee", 2.500000);
832     config_PutFloat(p_intf, "compressor-makeup-gain", 7.000000);
833
834     audio_output_t * p_aout = getAout();
835     if (p_aout) {
836         var_SetFloat(p_aout, "compressor-rms-peak", 0.000000);
837         var_SetFloat(p_aout, "compressor-attack", 25.000000);
838         var_SetFloat(p_aout, "compressor-release", 100.000000);
839         var_SetFloat(p_aout, "compressor-threshold", -11.000000);
840         var_SetFloat(p_aout, "compressor-ratio", 8.000000);
841         var_SetFloat(p_aout, "compressor-knee", 2.500000);
842         var_SetFloat(p_aout, "compressor-makeup-gain", 7.000000);
843         vlc_object_release(p_aout);
844     }
845     [self resetCompressor];
846 }
847
848 - (IBAction)comp_enable:(id)sender
849 {
850     [self setAudioFilter:"compressor" on:[sender state]];
851 }
852
853 - (IBAction)comp_sliderUpdated:(id)sender
854 {
855     audio_output_t * p_aout = getAout();
856     char * value;
857     if (sender == o_comp_band1_sld)
858         value = "compressor-rms-peak";
859     else if (sender == o_comp_band2_sld)
860         value = "compressor-attack";
861     else if (sender == o_comp_band3_sld)
862         value = "compressor-release";
863     else if (sender == o_comp_band4_sld)
864         value = "compressor-threshold";
865     else if (sender == o_comp_band5_sld)
866         value = "compressor-ratio";
867     else if (sender == o_comp_band6_sld)
868         value = "compressor-knee";
869     else if (sender == o_comp_band7_sld)
870         value = "compressor-makeup-gain";
871
872     if (p_aout) {
873         var_SetFloat(p_aout, value, [sender floatValue]);
874         vlc_object_release(p_aout);
875     }
876     config_PutFloat(p_intf, value, [sender floatValue]);
877
878     if (sender == o_comp_band1_sld)
879         [o_comp_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
880     else if (sender == o_comp_band2_sld)
881         [o_comp_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f ms", [sender floatValue]]];
882     else if (sender == o_comp_band3_sld)
883         [o_comp_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%3.1f ms", [sender floatValue]]];
884     else if (sender == o_comp_band4_sld)
885         [o_comp_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f dB", [sender floatValue]]];
886     else if (sender == o_comp_band5_sld)
887         [o_comp_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f:1", [sender floatValue]]];
888     else if (sender == o_comp_band6_sld)
889         [o_comp_band6_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [sender floatValue]]];
890     else if (sender == o_comp_band7_sld)
891         [o_comp_band7_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [sender floatValue]]];
892 }
893
894 #pragma mark -
895 #pragma mark Spatializer
896 - (void)resetSpatializer
897 {
898     char * psz_afilters;
899     psz_afilters = config_GetPsz(p_intf, "audio-filter");
900     if (psz_afilters) {
901         [o_spat_enable_ckb setState: (NSInteger)strstr(psz_afilters, "spatializer") ];
902         free(psz_afilters);
903     }
904     else
905         [o_spat_enable_ckb setState: NSOffState];
906
907 #define setSlider(bandsld, bandfld, var) \
908     [bandsld setFloatValue: config_GetFloat(p_intf, var) * 10.]; \
909     [bandfld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [bandsld floatValue]]]
910
911     setSlider(o_spat_band1_sld, o_spat_band1_fld, "spatializer-roomsize");
912     setSlider(o_spat_band2_sld, o_spat_band2_fld, "spatializer-width");
913     setSlider(o_spat_band3_sld, o_spat_band3_fld, "spatializer-wet");
914     setSlider(o_spat_band4_sld, o_spat_band4_fld, "spatializer-dry");
915     setSlider(o_spat_band5_sld, o_spat_band5_fld, "spatializer-damp");
916
917 #undef setSlider
918 }
919
920 - (IBAction)resetSpatializerValues:(id)sender
921 {
922     config_PutFloat(p_intf, "spatializer-roomsize", .85);
923     config_PutFloat(p_intf, "spatializer-width", 1.);
924     config_PutFloat(p_intf, "spatializer-wet", .4);
925     config_PutFloat(p_intf, "spatializer-dry", .5);
926     config_PutFloat(p_intf, "spatializer-damp", .5);
927
928     audio_output_t * p_aout = getAout();
929     if (p_aout) {
930         var_SetFloat(p_aout, "spatializer-roomsize", .85);
931         var_SetFloat(p_aout, "spatializer-width", 1.);
932         var_SetFloat(p_aout, "spatializer-wet", .4);
933         var_SetFloat(p_aout, "spatializer-dry", .5);
934         var_SetFloat(p_aout, "spatializer-damp", .5);
935         vlc_object_release(p_aout);
936     }
937     [self resetSpatializer];
938 }
939
940 - (IBAction)spat_enable:(id)sender
941 {
942     [self setAudioFilter:"spatializer" on:[sender state]];
943 }
944
945 - (IBAction)spat_sliderUpdated:(id)sender
946 {
947     audio_output_t * p_aout = getAout();
948     char * value;
949     if (sender == o_spat_band1_sld)
950         value = "spatializer-roomsize";
951     else if (sender == o_spat_band2_sld)
952         value = "spatializer-width";
953     else if (sender == o_spat_band3_sld)
954         value = "spatializer-wet";
955     else if (sender == o_spat_band4_sld)
956         value = "spatializer-dry";
957     else if (sender == o_spat_band5_sld)
958         value = "spatializer-damp";
959
960     if (p_aout) {
961         var_SetFloat(p_aout, value, [sender floatValue] / 10.);
962         vlc_object_release(p_aout);
963     }
964     config_PutFloat(p_intf, value, [sender floatValue] / 10.);
965
966     if (sender == o_spat_band1_sld)
967         [o_spat_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
968     else if (sender == o_spat_band2_sld)
969         [o_spat_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
970     else if (sender == o_spat_band3_sld)
971         [o_spat_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
972     else if (sender == o_spat_band4_sld)
973         [o_spat_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
974     else if (sender == o_spat_band5_sld)
975         [o_spat_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
976 }
977
978 #pragma mark -
979 #pragma mark Filter
980 - (void)resetAudioFilters
981 {
982     char * psz_afilters;
983     psz_afilters = config_GetPsz(p_intf, "audio-filter");
984     if (psz_afilters) {
985         [o_filter_headPhone_ckb setState: (NSInteger)strstr(psz_afilters, "headphone") ];
986         [o_filter_normLevel_ckb setState: (NSInteger)strstr(psz_afilters, "normvol") ];
987         [o_filter_normLevel_ckb setState: (NSInteger)strstr(psz_afilters, "karaoke") ];
988         free(psz_afilters);
989     } else {
990         [o_filter_headPhone_ckb setState: NSOffState];
991         [o_filter_normLevel_ckb setState: NSOffState];
992         [o_filter_karaoke_ckb setState: NSOffState];
993     }
994     [o_filter_normLevel_sld setFloatValue: config_GetFloat(p_intf, "norm-max-level")];
995 }
996
997 - (IBAction)filter_enableHeadPhoneVirt:(id)sender
998 {
999     [self setAudioFilter: "headphone" on:[sender state]];
1000 }
1001
1002 - (IBAction)filter_enableVolumeNorm:(id)sender
1003 {
1004     [self setAudioFilter: "normvol" on:[sender state]];
1005 }
1006
1007 - (IBAction)filter_volNormSliderUpdated:(id)sender
1008 {
1009     audio_output_t * p_aout= getAout();
1010
1011     if (p_aout) {
1012         var_SetFloat(p_aout, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1013         vlc_object_release(p_aout);
1014     }
1015
1016     config_PutFloat(p_intf, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1017 }
1018
1019 - (IBAction)filter_enableKaraoke:(id)sender
1020 {
1021     [self setAudioFilter: "karaoke" on:[sender state]];
1022 }
1023
1024 @end