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