1 /*****************************************************************************
2 * AudioEffects.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2004-2012 VLC authors and VideoLAN
7 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8 * Jérôme Decoodt <djc@videolan.org>
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.
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.
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 *****************************************************************************/
30 #import "AudioEffects.h"
31 #import "../../audio_filter/equalizer_presets.h"
32 #import "CompatibilityFixes.h"
33 #import "SharedDialogs.h"
35 #import <vlc_common.h>
36 #import <vlc_aout_intf.h>
37 #import <vlc_strings.h>
42 #pragma mark Initialization
44 @implementation VLCAudioEffects
45 static VLCAudioEffects *_o_sharedInstance = nil;
47 + (VLCAudioEffects *)sharedInstance
49 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
53 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
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];
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]]];
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];
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];
93 if (_o_sharedInstance)
97 _o_sharedInstance = [super init];
100 return _o_sharedInstance;
105 /* setup the user's language */
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")];
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")];
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")];
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")];
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];
147 [self setupEqualizer];
148 [self resetCompressor];
149 [self resetSpatializer];
150 [self resetAudioFilters];
151 [self resetProfileSelector];
155 #pragma mark internal functions
157 - (void)setAudioFilter: (char *)psz_name on:(BOOL)b_on
160 audio_output_t * p_aout = getAout();
162 psz_tmp = var_GetNonEmptyString(p_aout, "audio-filter");
164 psz_tmp = config_GetPsz(p_intf, "audio-filter");
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);
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);
183 aout_EnableFilter(pl_Get(p_intf), psz_name, b_on);
184 vlc_object_release(p_aout);
188 - (void)resetProfileSelector
190 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
191 [o_profile_pop removeAllItems];
193 NSArray * profileNames = [defaults objectForKey:@"AudioEffectProfileNames"];
194 [o_profile_pop addItemsWithTitles:profileNames];
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:)];
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:)];
207 [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"AudioEffectSelectedProfile"]];
208 [self profileSelectorAction:self];
212 #pragma mark generic code
213 - (IBAction)toggleWindow:(id)sender
215 if ([o_window isVisible])
216 [o_window orderOut:sender];
218 [o_window makeKeyAndOrderFront:sender];
221 - (IBAction)profileSelectorAction:(id)sender
223 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
224 NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
226 audio_output_t * p_aout = getAout();
227 playlist_t * p_playlist = pl_Get(p_intf);
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);
241 NSArray *items = [[[defaults objectForKey:@"AudioEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
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);
250 /* filter handling */
251 NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
254 /* enable the new filters, if we have an 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);
263 config_PutPsz(p_intf,"audio-filter",[tempString UTF8String]);
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]);
281 /* set values on-the-fly if we have an 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]);
300 if ([tempString rangeOfString:@"equalizer"].location == NSNotFound)
301 [o_eq_enable_ckb setState:NSOffState];
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];
310 /* store current profile selection */
311 [defaults setInteger:selectedProfile forKey:@"AudioEffectSelectedProfile"];
312 [defaults synchronize];
315 vlc_object_release(p_aout);
318 - (IBAction)addAudioEffectsProfile:(id)sender
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;
329 [panel runModalForWindow:o_window];
332 - (IBAction)removeAudioEffectsProfile:(id)sender
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;
344 [panel runModalForWindow:o_window];
348 #pragma mark Equalizer
349 static bool GetEqualizerStatus(intf_thread_t *p_custom_intf,
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));
357 psz_string = config_GetPsz(p_custom_intf, "audio-filter");
360 psz_string = var_GetNonEmptyString(p_object, "audio-filter");
362 vlc_object_release(p_object);
367 psz_parser = strstr(psz_string, psz_name);
377 - (void)setupEqualizer
379 vlc_object_t *p_object = VLC_OBJECT(getAout());
380 if (p_object == NULL)
381 p_object = vlc_object_hold(pl_Get(p_intf));
383 var_Create(p_object, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
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];
396 snprintf(psz_bands, sizeof(psz_bands),
397 "%.1f %.1f %.1f %.1f %.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]);
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);
416 [self updatePresetSelector];
418 [self equalizerUpdated];
421 - (void)updatePresetSelector
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:)];
433 vlc_object_t *p_object = VLC_OBJECT(getAout());
434 if (p_object == NULL)
435 p_object = vlc_object_hold(pl_Get(p_intf));
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];
447 [o_eq_presets_popup selectItemAtIndex:currentPresetIndex];
448 [o_eq_preamp_sld setFloatValue:[[[defaults objectForKey:@"EQPreampValues"] objectAtIndex:currentPresetIndex] floatValue]];
449 [self setBandSliderValuesForPreset:currentPresetIndex];
451 vlc_object_release(p_object);
454 - (void)equalizerUpdated
456 float f_preamp, f_band[10];
457 char *psz_bands, *psz_bands_init, *p_next;
459 bool b_enabled = GetEqualizerStatus(p_intf, (char *)"equalizer");
460 vlc_object_t *p_object = VLC_OBJECT(getAout());
462 if (p_object == NULL)
463 p_object = vlc_object_hold(pl_Get(p_intf));
465 var_Create(p_object, "equalizer-preamp", VLC_VAR_FLOAT |
467 var_Create(p_object, "equalizer-bands", VLC_VAR_STRING |
470 psz_bands = var_GetNonEmptyString(p_object, "equalizer-bands");
472 if (psz_bands == NULL)
473 psz_bands = strdup("0 0 0 0 0 0 0 0 0 0");
475 b_2p = (BOOL)config_GetInt(p_object, "equalizer-2pass");
476 f_preamp = config_GetFloat(p_object, "equalizer-preamp");
478 vlc_object_release(p_object);
481 [self updatePresetSelector];
483 /* Set the the checkboxes */
484 [o_eq_enable_ckb setState: b_enabled];
485 [o_eq_twopass_ckb setState: b_2p];
488 - (id)sliderByIndex:(int)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;
505 - (void)setBandSlidersValues:(float *)values
507 for (int i = 0 ; i<= 9 ; i++)
508 [self setValue:values[i] forSlider:i];
511 - (void)setBandSliderValuesForPreset:(NSInteger)presetID
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];
520 - (void)initBandSliders
522 for (int i = 0 ; i< 9 ; i++)
523 [self setValue:0.0 forSlider:i];
526 - (NSString *)generatePresetString
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]];
541 - (void)setValue:(float)value forSlider:(int)index
543 id slider = [self sliderByIndex:index];
546 [slider setFloatValue:value];
549 - (IBAction)eq_enable:(id)sender
551 [self setAudioFilter: "equalizer" on:[sender state]];
554 - (IBAction)eq_bandSliderUpdated:(id)sender
556 vlc_object_t *p_object = VLC_OBJECT(getAout());
558 if (p_object == NULL)
559 p_object = vlc_object_hold(pl_Get(p_intf));
561 var_SetString(p_object, "equalizer-bands", [[self generatePresetString] UTF8String]);
563 /* save changed to config */
564 config_PutPsz(p_intf, "equalizer-bands", [[self generatePresetString] UTF8String]);
566 vlc_object_release(p_object);
569 - (IBAction)eq_changePreset:(id)sender
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];
577 NSString *preset = [[defaults objectForKey:@"EQValues"] objectAtIndex:numberOfChosenPreset];
578 NSString *preamp = [[defaults objectForKey:@"EQPreampValues"] objectAtIndex:numberOfChosenPreset];
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]);
584 [o_eq_preamp_sld setFloatValue: [preamp floatValue]];
585 [self setBandSliderValuesForPreset:numberOfChosenPreset];
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]);
592 vlc_object_release(p_object);
595 - (IBAction)eq_preampSliderUpdated:(id)sender
597 float f_preamp = [sender floatValue] ;
599 vlc_object_t *p_object = VLC_OBJECT(getAout());
600 if (p_object == NULL)
601 p_object = vlc_object_hold(pl_Get(p_intf));
603 var_SetFloat(p_object, "equalizer-preamp", f_preamp);
605 /* save changed to config */
606 config_PutFloat(p_intf, "equalizer-preamp", f_preamp);
608 vlc_object_release(p_object);
610 - (IBAction)eq_twopass:(id)sender
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));
618 var_SetBool(p_object, "equalizer-2pass", b_2p);
620 /* save changed to config */
621 config_PutInt(p_intf, "equalizer-2pass", (int)b_2p);
623 vlc_object_release(p_object);
626 - (IBAction)addPresetAction:(id)sender
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;
637 [panel runModalForWindow:o_window];
640 - (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
642 if (value == NSOKButton) {
643 if ([text length] > 0) {
644 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
646 if (!b_genericAudioProfileInInteraction) {
648 NSMutableArray * workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQValues"]];
649 [workArray addObject:[self generatePresetString]];
650 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQValues"];
652 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
653 [workArray addObject:text];
654 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
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"];
660 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
661 [workArray addObject:[text decomposedStringWithCanonicalMapping]];
662 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
664 [defaults synchronize];
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));
671 var_SetString(p_object , "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
672 config_PutPsz(p_object, "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
674 vlc_object_release(p_object);
677 [self updatePresetSelector];
679 vlc_object_t *p_object = VLC_OBJECT(getAout());
680 if (p_object == NULL)
681 p_object = vlc_object_hold(pl_Get(p_intf));
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];
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")];
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"];
716 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
717 [workArray addObject:text];
718 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
722 [defaults synchronize];
723 vlc_object_release(p_object);
728 [self resetProfileSelector];
731 - (IBAction)deletePresetAction:(id)sender
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;
742 [panel runModalForWindow:o_window];
745 - (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
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"];
755 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
756 [workArray removeObjectAtIndex:item];
757 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
759 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQPreampValues"]];
760 [workArray removeObjectAtIndex:item];
761 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQPreampValues"];
763 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
764 [workArray removeObjectAtIndex:item];
765 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
767 [defaults synchronize];
770 [self updatePresetSelector];
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"];
778 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
779 [workArray removeObjectAtIndex:item];
780 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
784 [defaults synchronize];
785 [self resetProfileSelector];
791 #pragma mark Compressor
792 - (void)resetCompressor
795 psz_afilters = config_GetPsz(p_intf, "audio-filter");
797 [o_comp_enable_ckb setState: (NSInteger)strstr(psz_afilters, "compressor") ];
801 [o_comp_enable_ckb setState: NSOffState];
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]]];
819 - (IBAction)resetCompressorValues:(id)sender
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);
829 audio_output_t * p_aout = getAout();
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);
840 [self resetCompressor];
843 - (IBAction)comp_enable:(id)sender
845 [self setAudioFilter:"compressor" on:[sender state]];
848 - (IBAction)comp_sliderUpdated:(id)sender
850 audio_output_t * p_aout = getAout();
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";
868 var_SetFloat(p_aout, value, [sender floatValue]);
869 vlc_object_release(p_aout);
871 config_PutFloat(p_intf, value, [sender floatValue]);
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]]];
890 #pragma mark Spatializer
891 - (void)resetSpatializer
894 psz_afilters = config_GetPsz(p_intf, "audio-filter");
896 [o_spat_enable_ckb setState: (NSInteger)strstr(psz_afilters, "spatializer") ];
900 [o_spat_enable_ckb setState: NSOffState];
902 #define setSlider(bandsld, bandfld, var) \
903 [bandsld setFloatValue: config_GetFloat(p_intf, var) * 10.]; \
904 [bandfld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [bandsld floatValue]]]
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");
915 - (IBAction)resetSpatializerValues:(id)sender
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);
923 audio_output_t * p_aout = getAout();
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);
932 [self resetSpatializer];
935 - (IBAction)spat_enable:(id)sender
937 [self setAudioFilter:"spatializer" on:[sender state]];
940 - (IBAction)spat_sliderUpdated:(id)sender
942 audio_output_t * p_aout = getAout();
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";
956 var_SetFloat(p_aout, value, [sender floatValue] / 10.);
957 vlc_object_release(p_aout);
959 config_PutFloat(p_intf, value, [sender floatValue] / 10.);
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]]];
975 - (void)resetAudioFilters
978 psz_afilters = config_GetPsz(p_intf, "audio-filter");
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") ];
985 [o_filter_headPhone_ckb setState: NSOffState];
986 [o_filter_normLevel_ckb setState: NSOffState];
987 [o_filter_karaoke_ckb setState: NSOffState];
989 [o_filter_normLevel_sld setFloatValue: config_GetFloat(p_intf, "norm-max-level")];
992 - (IBAction)filter_enableHeadPhoneVirt:(id)sender
994 [self setAudioFilter: "headphone" on:[sender state]];
997 - (IBAction)filter_enableVolumeNorm:(id)sender
999 [self setAudioFilter: "normvol" on:[sender state]];
1002 - (IBAction)filter_volNormSliderUpdated:(id)sender
1004 audio_output_t * p_aout= getAout();
1007 var_SetFloat(p_aout, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1008 vlc_object_release(p_aout);
1011 config_PutFloat(p_intf, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1014 - (IBAction)filter_enableKaraoke:(id)sender
1016 [self setAudioFilter: "karaoke" on:[sender state]];