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