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_strings.h>
40 @interface VLCAudioEffects (Internal)
41 - (void)resetProfileSelector;
42 - (void)updatePresetSelector;
43 - (void)setBandSliderValuesForPreset:(NSInteger)presetID;
47 #pragma mark Initialization
49 @implementation VLCAudioEffects
50 static VLCAudioEffects *_o_sharedInstance = nil;
52 + (VLCAudioEffects *)sharedInstance
54 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
58 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
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];
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]]];
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];
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];
98 if (_o_sharedInstance)
102 _o_sharedInstance = [super init];
105 return _o_sharedInstance;
110 /* setup the user's language */
112 [o_eq_enable_ckb setTitle:_NS("Enable")];
113 [o_eq_twopass_ckb setTitle:_NS("2 Pass")];
114 [o_eq_preamp_lbl setStringValue:_NS("Preamp")];
117 [o_comp_enable_ckb setTitle:_NS("Enable dynamic range compressor")];
118 [o_comp_reset_btn setTitle:_NS("Reset")];
119 [o_comp_band1_lbl setStringValue:_NS("RMS/peak")];;
120 [o_comp_band2_lbl setStringValue:_NS("Attack")];
121 [o_comp_band3_lbl setStringValue:_NS("Release")];
122 [o_comp_band4_lbl setStringValue:_NS("Threshold")];
123 [o_comp_band5_lbl setStringValue:_NS("Ratio")];
124 [o_comp_band6_lbl setStringValue:_NS("Knee radius")];
125 [o_comp_band7_lbl setStringValue:_NS("Makeup gain")];
128 [o_spat_enable_ckb setTitle:_NS("Enable Spatializer")];
129 [o_spat_reset_btn setTitle:_NS("Reset")];
130 [o_spat_band1_lbl setStringValue:_NS("Size")];
131 [o_spat_band2_lbl setStringValue:_NS("Width")];
132 [o_spat_band3_lbl setStringValue:_NS("Wet")];
133 [o_spat_band4_lbl setStringValue:_NS("Dry")];
134 [o_spat_band5_lbl setStringValue:_NS("Damp")];
137 [o_filter_headPhone_ckb setTitle:_NS("Headphone virtualization")];
138 [o_filter_normLevel_ckb setTitle:_NS("Volume normalization")];
139 [o_filter_normLevel_lbl setStringValue:_NS("Maximum level")];
140 [o_filter_karaoke_ckb setTitle:_NS("Karaoke")];
143 [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"equalizer"]] setLabel:_NS("Equalizer")];
144 [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"compressor"]] setLabel:_NS("Compressor")];
145 [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"spatializer"]] setLabel:_NS("Spatializer")];
146 [[o_tableView tabViewItemAtIndex:[o_tableView indexOfTabViewItemWithIdentifier:@"filter"]] setLabel:_NS("Filter")];
147 [o_window setTitle:_NS("Audio Effects")];
148 [o_window setExcludedFromWindowsMenu:YES];
149 if (!OSX_SNOW_LEOPARD)
150 [o_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
152 [self setupEqualizer];
153 [self resetCompressor];
154 [self resetSpatializer];
155 [self resetAudioFilters];
156 [self resetProfileSelector];
160 #pragma mark internal functions
162 - (void)setAudioFilter: (char *)psz_name on:(BOOL)b_on
165 audio_output_t * p_aout = getAout();
167 psz_tmp = var_GetNonEmptyString(p_aout, "audio-filter");
169 psz_tmp = config_GetPsz(p_intf, "audio-filter");
173 config_PutPsz(p_intf, "audio-filter", psz_name);
174 else if ((NSInteger)strstr(psz_tmp, psz_name) == NO) {
175 psz_tmp = (char *)[[NSString stringWithFormat: @"%s:%s", psz_tmp, psz_name] UTF8String];
176 config_PutPsz(p_intf, "audio-filter", psz_tmp);
180 psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@":%s",psz_name]]] UTF8String];
181 psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@"%s:",psz_name]]] UTF8String];
182 psz_tmp = (char *)[[[NSString stringWithUTF8String: psz_tmp] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithUTF8String:psz_name]]] UTF8String];
183 config_PutPsz(p_intf, "audio-filter", psz_tmp);
188 playlist_EnableAudioFilter(pl_Get(p_intf), psz_name, b_on);
189 vlc_object_release(p_aout);
193 - (void)resetProfileSelector
195 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
196 [o_profile_pop removeAllItems];
198 NSArray * profileNames = [defaults objectForKey:@"AudioEffectProfileNames"];
199 [o_profile_pop addItemsWithTitles:profileNames];
201 [[o_profile_pop menu] addItem:[NSMenuItem separatorItem]];
202 [o_profile_pop addItemWithTitle:_NS("Save selection as new profile...")];
203 [[o_profile_pop lastItem] setTarget: self];
204 [[o_profile_pop lastItem] setAction: @selector(addAudioEffectsProfile:)];
206 if ([profileNames count] > 1) {
207 [o_profile_pop addItemWithTitle:_NS("Organize Profiles...")];
208 [[o_profile_pop lastItem] setTarget: self];
209 [[o_profile_pop lastItem] setAction: @selector(removeAudioEffectsProfile:)];
212 [o_profile_pop selectItemAtIndex:[defaults integerForKey:@"AudioEffectSelectedProfile"]];
213 [self profileSelectorAction:self];
217 #pragma mark generic code
218 - (IBAction)toggleWindow:(id)sender
220 if ([o_window isVisible])
221 [o_window orderOut:sender];
223 [o_window makeKeyAndOrderFront:sender];
226 - (IBAction)profileSelectorAction:(id)sender
228 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
229 NSUInteger selectedProfile = [o_profile_pop indexOfSelectedItem];
231 audio_output_t * p_aout = getAout();
232 playlist_t * p_playlist = pl_Get(p_intf);
235 /* disable existing filters */
236 playlist_EnableAudioFilter(p_playlist, "equalizer", false);
237 playlist_EnableAudioFilter(p_playlist, "compressor", false);
238 playlist_EnableAudioFilter(p_playlist, "spatializer", false);
239 playlist_EnableAudioFilter(p_playlist, "compressor", false);
240 playlist_EnableAudioFilter(p_playlist, "headphone", false);
241 playlist_EnableAudioFilter(p_playlist, "normvol", false);
242 playlist_EnableAudioFilter(p_playlist, "karaoke", false);
246 NSArray *items = [[[defaults objectForKey:@"AudioEffectProfiles"] objectAtIndex:selectedProfile] componentsSeparatedByString:@";"];
249 vlc_object_t *p_object = VLC_OBJECT(getAout());
250 if (p_object == NULL)
251 p_object = vlc_object_hold(pl_Get(p_intf));
252 var_SetString(p_object,"equalizer-preset",vlc_b64_decode([[items objectAtIndex:0] UTF8String]));
253 vlc_object_release(p_object);
255 /* filter handling */
256 NSString *tempString = [NSString stringWithFormat:@"%s", vlc_b64_decode([[items objectAtIndex:1] UTF8String])];
259 /* enable the new filters, if we have an aout */
261 if ([tempString length] > 0) {
262 tempArray = [tempString componentsSeparatedByString:@":"];
263 count = [tempArray count];
264 for (NSUInteger x = 0; x < count; x++)
265 playlist_EnableAudioFilter(p_playlist, (char *)[[tempArray objectAtIndex:x] UTF8String], true);
268 config_PutPsz(p_intf,"audio-filter",[tempString UTF8String]);
271 config_PutFloat(p_intf, "compressor-rms-peak",[[items objectAtIndex:2] floatValue]);
272 config_PutFloat(p_intf, "compressor-attack",[[items objectAtIndex:3] floatValue]);
273 config_PutFloat(p_intf, "compressor-release",[[items objectAtIndex:4] floatValue]);
274 config_PutFloat(p_intf, "compressor-threshold",[[items objectAtIndex:5] floatValue]);
275 config_PutFloat(p_intf, "compressor-ratio",[[items objectAtIndex:6] floatValue]);
276 config_PutFloat(p_intf, "compressor-knee",[[items objectAtIndex:7] floatValue]);
277 config_PutFloat(p_intf, "compressor-makeup-gain",[[items objectAtIndex:8] floatValue]);
278 config_PutFloat(p_intf, "spatializer-roomsize",[[items objectAtIndex:9] floatValue]);
279 config_PutFloat(p_intf, "spatializer-width",[[items objectAtIndex:10] floatValue]);
280 config_PutFloat(p_intf, "spatializer-wet",[[items objectAtIndex:11] floatValue]);
281 config_PutFloat(p_intf, "spatializer-dry",[[items objectAtIndex:12] floatValue]);
282 config_PutFloat(p_intf, "spatializer-damp",[[items objectAtIndex:13] floatValue]);
283 config_PutFloat(p_intf, "norm-max-level",[[items objectAtIndex:14] floatValue]);
284 config_PutInt(p_intf, "equalizer-2pass",[[items objectAtIndex:15] intValue]);
286 /* set values on-the-fly if we have an aout */
288 var_SetFloat(p_aout, "compressor-rms-peak", [[items objectAtIndex:2] floatValue]);
289 var_SetFloat(p_aout, "compressor-attack", [[items objectAtIndex:3] floatValue]);
290 var_SetFloat(p_aout, "compressor-release", [[items objectAtIndex:4] floatValue]);
291 var_SetFloat(p_aout, "compressor-threshold", [[items objectAtIndex:5] floatValue]);
292 var_SetFloat(p_aout, "compressor-ratio", [[items objectAtIndex:6] floatValue]);
293 var_SetFloat(p_aout, "compressor-knee", [[items objectAtIndex:7] floatValue]);
294 var_SetFloat(p_aout, "compressor-makeup-gain", [[items objectAtIndex:8] floatValue]);
295 var_SetFloat(p_aout, "spatializer-roomsize", [[items objectAtIndex:9] floatValue]);
296 var_SetFloat(p_aout, "spatializer-width", [[items objectAtIndex:10] floatValue]);
297 var_SetFloat(p_aout, "spatializer-wet", [[items objectAtIndex:11] floatValue]);
298 var_SetFloat(p_aout, "spatializer-dry", [[items objectAtIndex:12] floatValue]);
299 var_SetFloat(p_aout, "spatializer-damp", [[items objectAtIndex:13] floatValue]);
300 var_SetFloat(p_aout, "norm-max-level", [[items objectAtIndex:14] floatValue]);
301 var_SetBool(p_aout, "equalizer-2pass", (BOOL)[[items objectAtIndex:15] intValue]);
305 if ([tempString rangeOfString:@"equalizer"].location == NSNotFound)
306 [o_eq_enable_ckb setState:NSOffState];
308 [o_eq_enable_ckb setState:NSOnState];
309 [o_eq_twopass_ckb setState:[[items objectAtIndex:15] intValue]];
310 [self resetCompressor];
311 [self resetSpatializer];
312 [self resetAudioFilters];
313 [self updatePresetSelector];
315 /* store current profile selection */
316 [defaults setInteger:selectedProfile forKey:@"AudioEffectSelectedProfile"];
317 [defaults synchronize];
320 vlc_object_release(p_aout);
323 - (IBAction)addAudioEffectsProfile:(id)sender
326 VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
327 [panel setTitle: _NS("Save current selection as new profile")];
328 [panel setSubTitle: _NS("Enter a name for the new profile:")];
329 [panel setCancelButtonLabel: _NS("Cancel")];
330 [panel setOKButtonLabel: _NS("Save")];
331 [panel setTarget:self];
332 b_genericAudioProfileInInteraction = YES;
334 [panel runModalForWindow:o_window];
337 - (IBAction)removeAudioEffectsProfile:(id)sender
340 VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
341 [panel setTitle:_NS("Remove a preset")];
342 [panel setSubTitle:_NS("Select the preset you would like to remove:")];
343 [panel setOKButtonLabel:_NS("Remove")];
344 [panel setCancelButtonLabel:_NS("Cancel")];
345 [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"AudioEffectProfileNames"]];
346 [panel setTarget:self];
347 b_genericAudioProfileInInteraction = YES;
349 [panel runModalForWindow:o_window];
353 #pragma mark Equalizer
354 static bool GetEqualizerStatus(intf_thread_t *p_custom_intf,
357 char *psz_parser, *psz_string = NULL;
358 vlc_object_t *p_object = VLC_OBJECT(getAout());
359 if (p_object == NULL)
360 p_object = vlc_object_hold(pl_Get(p_custom_intf));
362 psz_string = config_GetPsz(p_custom_intf, "audio-filter");
365 psz_string = var_GetNonEmptyString(p_object, "audio-filter");
367 vlc_object_release(p_object);
372 psz_parser = strstr(psz_string, psz_name);
382 - (void)setupEqualizer
384 vlc_object_t *p_object = VLC_OBJECT(getAout());
385 if (p_object == NULL)
386 p_object = vlc_object_hold(pl_Get(p_intf));
388 var_Create(p_object, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
390 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
391 NSArray * presets = [defaults objectForKey:@"EQNames"];
392 NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
393 NSInteger currentPresetIndex = 0;
394 if ([currentPreset length] > 0) {
395 currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
396 return [obj isEqualToString:currentPreset];
401 snprintf(psz_bands, sizeof(psz_bands),
402 "%.1f %.1f %.1f %.1f %.1f %.1f %.1f "
404 eqz_preset_10b[currentPresetIndex].f_amp[0],
405 eqz_preset_10b[currentPresetIndex].f_amp[1],
406 eqz_preset_10b[currentPresetIndex].f_amp[2],
407 eqz_preset_10b[currentPresetIndex].f_amp[3],
408 eqz_preset_10b[currentPresetIndex].f_amp[4],
409 eqz_preset_10b[currentPresetIndex].f_amp[5],
410 eqz_preset_10b[currentPresetIndex].f_amp[6],
411 eqz_preset_10b[currentPresetIndex].f_amp[7],
412 eqz_preset_10b[currentPresetIndex].f_amp[8],
413 eqz_preset_10b[currentPresetIndex].f_amp[9]);
415 var_Create(p_object, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
416 var_Create(p_object, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
417 var_SetFloat(p_object, "equalizer-preamp", eqz_preset_10b[currentPresetIndex].f_preamp);
418 var_SetString(p_object, "equalizer-bands", psz_bands);
419 vlc_object_release(p_object);
421 [self updatePresetSelector];
423 [self equalizerUpdated];
426 - (void)updatePresetSelector
428 [o_eq_presets_popup removeAllItems];
429 [o_eq_presets_popup addItemsWithTitles:[[NSUserDefaults standardUserDefaults] objectForKey:@"EQTitles"]];
430 [[o_eq_presets_popup menu] addItem:[NSMenuItem separatorItem]];
431 [o_eq_presets_popup addItemWithTitle:_NS("Add new Preset...")];
432 [[o_eq_presets_popup lastItem] setTarget: self];
433 [[o_eq_presets_popup lastItem] setAction: @selector(addPresetAction:)];
434 [o_eq_presets_popup addItemWithTitle:_NS("Organize Presets...")];
435 [[o_eq_presets_popup lastItem] setTarget: self];
436 [[o_eq_presets_popup lastItem] setAction: @selector(deletePresetAction:)];
438 vlc_object_t *p_object = VLC_OBJECT(getAout());
439 if (p_object == NULL)
440 p_object = vlc_object_hold(pl_Get(p_intf));
442 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
443 NSArray * presets = [defaults objectForKey:@"EQNames"];
444 NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
445 NSInteger currentPresetIndex = 0;
446 if ([currentPreset length] > 0) {
447 currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
448 return [obj isEqualToString:currentPreset];
452 [o_eq_presets_popup selectItemAtIndex:currentPresetIndex];
453 [o_eq_preamp_sld setFloatValue:[[[defaults objectForKey:@"EQPreampValues"] objectAtIndex:currentPresetIndex] floatValue]];
454 [self setBandSliderValuesForPreset:currentPresetIndex];
456 vlc_object_release(p_object);
459 - (void)equalizerUpdated
461 float f_preamp, f_band[10];
462 char *psz_bands, *psz_bands_init, *p_next;
464 bool b_enabled = GetEqualizerStatus(p_intf, (char *)"equalizer");
465 vlc_object_t *p_object = VLC_OBJECT(getAout());
467 if (p_object == NULL)
468 p_object = vlc_object_hold(pl_Get(p_intf));
470 var_Create(p_object, "equalizer-preamp", VLC_VAR_FLOAT |
472 var_Create(p_object, "equalizer-bands", VLC_VAR_STRING |
475 psz_bands = var_GetNonEmptyString(p_object, "equalizer-bands");
477 if (psz_bands == NULL)
478 psz_bands = strdup("0 0 0 0 0 0 0 0 0 0");
480 b_2p = (BOOL)config_GetInt(p_object, "equalizer-2pass");
481 f_preamp = config_GetFloat(p_object, "equalizer-preamp");
483 vlc_object_release(p_object);
486 [self updatePresetSelector];
488 /* Set the the checkboxes */
489 [o_eq_enable_ckb setState: b_enabled];
490 [o_eq_twopass_ckb setState: b_2p];
493 - (id)sliderByIndex:(int)index
496 case 0 : return o_eq_band1_sld;
497 case 1 : return o_eq_band2_sld;
498 case 2 : return o_eq_band3_sld;
499 case 3 : return o_eq_band4_sld;
500 case 4 : return o_eq_band5_sld;
501 case 5 : return o_eq_band6_sld;
502 case 6 : return o_eq_band7_sld;
503 case 7 : return o_eq_band8_sld;
504 case 8 : return o_eq_band9_sld;
505 case 9 : return o_eq_band10_sld;
506 default : return nil;
510 - (void)setBandSlidersValues:(float *)values
512 for (int i = 0 ; i<= 9 ; i++)
513 [self setValue:values[i] forSlider:i];
516 - (void)setBandSliderValuesForPreset:(NSInteger)presetID
518 NSString * preset = [[[NSUserDefaults standardUserDefaults] objectForKey:@"EQValues"] objectAtIndex:presetID];
519 NSArray * values = [preset componentsSeparatedByString:@" "];
520 NSUInteger count = [values count];
521 for (NSUInteger x = 0; x < count; x++)
522 [self setValue:[[values objectAtIndex:x] floatValue] forSlider:x];
525 - (void)initBandSliders
527 for (int i = 0 ; i< 9 ; i++)
528 [self setValue:0.0 forSlider:i];
531 - (NSString *)generatePresetString
533 return [NSString stringWithFormat:@"%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f",
534 [o_eq_band1_sld floatValue],
535 [o_eq_band2_sld floatValue],
536 [o_eq_band3_sld floatValue],
537 [o_eq_band4_sld floatValue],
538 [o_eq_band5_sld floatValue],
539 [o_eq_band6_sld floatValue],
540 [o_eq_band7_sld floatValue],
541 [o_eq_band8_sld floatValue],
542 [o_eq_band9_sld floatValue],
543 [o_eq_band10_sld floatValue]];
546 - (void)setValue:(float)value forSlider:(int)index
548 id slider = [self sliderByIndex:index];
551 [slider setFloatValue:value];
554 - (IBAction)eq_enable:(id)sender
556 [self setAudioFilter: "equalizer" on:[sender state]];
559 - (IBAction)eq_bandSliderUpdated:(id)sender
561 vlc_object_t *p_object = VLC_OBJECT(getAout());
563 if (p_object == NULL)
564 p_object = vlc_object_hold(pl_Get(p_intf));
566 var_SetString(p_object, "equalizer-bands", [[self generatePresetString] UTF8String]);
568 /* save changed to config */
569 config_PutPsz(p_intf, "equalizer-bands", [[self generatePresetString] UTF8String]);
571 vlc_object_release(p_object);
574 - (IBAction)eq_changePreset:(id)sender
576 vlc_object_t *p_object= VLC_OBJECT(getAout());
577 if (p_object == NULL)
578 p_object = vlc_object_hold(pl_Get(p_intf));
579 NSInteger numberOfChosenPreset = [sender indexOfSelectedItem];
580 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
582 NSString *preset = [[defaults objectForKey:@"EQValues"] objectAtIndex:numberOfChosenPreset];
583 NSString *preamp = [[defaults objectForKey:@"EQPreampValues"] objectAtIndex:numberOfChosenPreset];
585 var_SetString(p_object, "equalizer-bands", [preset UTF8String]);
586 var_SetFloat(p_object, "equalizer-preamp", [preamp floatValue]);
587 var_SetString(p_object , "equalizer-preset" , [[[defaults objectForKey:@"EQNames"] objectAtIndex:numberOfChosenPreset] UTF8String]);
589 [o_eq_preamp_sld setFloatValue: [preamp floatValue]];
590 [self setBandSliderValuesForPreset:numberOfChosenPreset];
592 /* save changed to config */
593 config_PutPsz(p_intf, "equalizer-bands", [preset UTF8String]);
594 config_PutFloat(p_intf, "equalizer-preamp", [preamp floatValue]);
595 config_PutPsz(p_intf, "equalizer-preset", [[[defaults objectForKey:@"EQNames"] objectAtIndex:numberOfChosenPreset] UTF8String]);
597 vlc_object_release(p_object);
600 - (IBAction)eq_preampSliderUpdated:(id)sender
602 float f_preamp = [sender floatValue] ;
604 vlc_object_t *p_object = VLC_OBJECT(getAout());
605 if (p_object == NULL)
606 p_object = vlc_object_hold(pl_Get(p_intf));
608 var_SetFloat(p_object, "equalizer-preamp", f_preamp);
610 /* save changed to config */
611 config_PutFloat(p_intf, "equalizer-preamp", f_preamp);
613 vlc_object_release(p_object);
615 - (IBAction)eq_twopass:(id)sender
617 bool b_2p = [sender state] ? true : false;
618 audio_output_t *p_aout = getAout();
619 vlc_object_t *p_object= VLC_OBJECT(p_aout);
620 if (p_object == NULL)
621 p_object = vlc_object_hold(pl_Get(p_intf));
623 var_SetBool(p_object, "equalizer-2pass", b_2p);
625 /* save changed to config */
626 config_PutInt(p_intf, "equalizer-2pass", (int)b_2p);
628 vlc_object_release(p_object);
631 - (IBAction)addPresetAction:(id)sender
634 VLCEnterTextPanel * panel = [VLCEnterTextPanel sharedInstance];
635 [panel setTitle: _NS("Save current selection as new preset")];
636 [panel setSubTitle: _NS("Enter a name for the new preset:")];
637 [panel setCancelButtonLabel: _NS("Cancel")];
638 [panel setOKButtonLabel: _NS("Save")];
639 [panel setTarget:self];
640 b_genericAudioProfileInInteraction = NO;
642 [panel runModalForWindow:o_window];
645 - (void)panel:(VLCEnterTextPanel *)panel returnValue:(NSUInteger)value text:(NSString *)text
647 if (value == NSOKButton) {
648 if ([text length] > 0) {
649 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
651 if (!b_genericAudioProfileInInteraction) {
653 NSMutableArray * workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQValues"]];
654 [workArray addObject:[self generatePresetString]];
655 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQValues"];
657 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
658 [workArray addObject:text];
659 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
661 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQPreampValues"]];
662 [workArray addObject:[NSString stringWithFormat:@"%.1f", [o_eq_preamp_sld floatValue]]];
663 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQPreampValues"];
665 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
666 [workArray addObject:[text decomposedStringWithCanonicalMapping]];
667 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
669 [defaults synchronize];
671 /* update VLC internals */
672 vlc_object_t *p_object= VLC_OBJECT(getAout());
673 if (p_object == NULL)
674 p_object = vlc_object_hold(pl_Get(p_intf));
676 var_SetString(p_object , "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
677 config_PutPsz(p_object, "equalizer-preset", [[text decomposedStringWithCanonicalMapping] UTF8String]);
679 vlc_object_release(p_object);
682 [self updatePresetSelector];
684 vlc_object_t *p_object = VLC_OBJECT(getAout());
685 if (p_object == NULL)
686 p_object = vlc_object_hold(pl_Get(p_intf));
688 NSArray * presets = [defaults objectForKey:@"EQNames"];
689 NSString * currentPreset = [NSString stringWithFormat:@"%s",var_GetNonEmptyString(p_object, "equalizer-preset")];
690 NSInteger currentPresetIndex = 0;
691 if ([currentPreset length] > 0) {
692 currentPresetIndex = [presets indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
693 return [obj isEqualToString:currentPreset];
696 NSString *newProfile = [NSString stringWithFormat:@"%s;%s;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%f;%lli",
697 vlc_b64_encode(var_GetNonEmptyString(p_object, "equalizer-preset")),
698 vlc_b64_encode(config_GetPsz(p_intf, "audio-filter")),
699 config_GetFloat(p_intf, "compressor-rms-peak"),
700 config_GetFloat(p_intf, "compressor-attack"),
701 config_GetFloat(p_intf, "compressor-release"),
702 config_GetFloat(p_intf, "compressor-threshold"),
703 config_GetFloat(p_intf, "compressor-ratio"),
704 config_GetFloat(p_intf, "compressor-knee"),
705 config_GetFloat(p_intf, "compressor-makeup-gain"),
706 config_GetFloat(p_intf, "spatializer-roomsize"),
707 config_GetFloat(p_intf, "spatializer-width"),
708 config_GetFloat(p_intf, "spatializer-wet"),
709 config_GetFloat(p_intf, "spatializer-dry"),
710 config_GetFloat(p_intf, "spatializer-damp"),
711 config_GetFloat(p_intf, "norm-max-level"),
712 config_GetInt(p_intf,"equalizer-2pass")];
714 /* add string to user defaults as well as a label */
715 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
716 NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfiles"]];
717 [workArray addObject:newProfile];
718 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfiles"];
719 [defaults setInteger:[workArray count] - 1 forKey:@"AudioEffectSelectedProfile"];
721 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
722 [workArray addObject:text];
723 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
727 [defaults synchronize];
728 vlc_object_release(p_object);
733 [self resetProfileSelector];
736 - (IBAction)deletePresetAction:(id)sender
738 VLCSelectItemInPopupPanel * panel = [VLCSelectItemInPopupPanel sharedInstance];
739 [panel setTitle:_NS("Remove a preset")];
740 [panel setSubTitle:_NS("Select the preset you would like to remove:")];
741 [panel setOKButtonLabel:_NS("Remove")];
742 [panel setCancelButtonLabel:_NS("Cancel")];
743 [panel setPopupButtonContent:[[NSUserDefaults standardUserDefaults] objectForKey:@"EQTitles"]];
744 [panel setTarget:self];
745 b_genericAudioProfileInInteraction = NO;
747 [panel runModalForWindow:o_window];
750 - (void)panel:(VLCSelectItemInPopupPanel *)panel returnValue:(NSUInteger)value item:(NSUInteger)item
752 if (value == NSOKButton) {
753 if (!b_genericAudioProfileInInteraction) {
754 /* remove requested profile from the arrays */
755 NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
756 NSMutableArray * workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQValues"]];
757 [workArray removeObjectAtIndex:item];
758 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQValues"];
760 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQTitles"]];
761 [workArray removeObjectAtIndex:item];
762 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQTitles"];
764 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQPreampValues"]];
765 [workArray removeObjectAtIndex:item];
766 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQPreampValues"];
768 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"EQNames"]];
769 [workArray removeObjectAtIndex:item];
770 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"EQNames"];
772 [defaults synchronize];
775 [self updatePresetSelector];
777 /* remove selected profile from settings */
778 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
779 NSMutableArray *workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfiles"]];
780 [workArray removeObjectAtIndex:item];
781 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfiles"];
783 workArray = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:@"AudioEffectProfileNames"]];
784 [workArray removeObjectAtIndex:item];
785 [defaults setObject:[NSArray arrayWithArray:workArray] forKey:@"AudioEffectProfileNames"];
789 [defaults synchronize];
790 [self resetProfileSelector];
796 #pragma mark Compressor
797 - (void)resetCompressor
800 psz_afilters = config_GetPsz(p_intf, "audio-filter");
802 [o_comp_enable_ckb setState: (NSInteger)strstr(psz_afilters, "compressor") ];
806 [o_comp_enable_ckb setState: NSOffState];
808 [o_comp_band1_sld setFloatValue: config_GetFloat(p_intf, "compressor-rms-peak")];
809 [o_comp_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [o_comp_band1_sld floatValue]]];
810 [o_comp_band2_sld setFloatValue: config_GetFloat(p_intf, "compressor-attack")];
811 [o_comp_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f ms", [o_comp_band2_sld floatValue]]];
812 [o_comp_band3_sld setFloatValue: config_GetFloat(p_intf, "compressor-release")];
813 [o_comp_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%3.1f ms", [o_comp_band3_sld floatValue]]];
814 [o_comp_band4_sld setFloatValue: config_GetFloat(p_intf, "compressor-threshold")];
815 [o_comp_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f dB", [o_comp_band4_sld floatValue]]];
816 [o_comp_band5_sld setFloatValue: config_GetFloat(p_intf, "compressor-ratio")];
817 [o_comp_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f:1", [o_comp_band5_sld floatValue]]];
818 [o_comp_band6_sld setFloatValue: config_GetFloat(p_intf, "compressor-knee")];
819 [o_comp_band6_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [o_comp_band6_sld floatValue]]];
820 [o_comp_band7_sld setFloatValue: config_GetFloat(p_intf, "compressor-makeup-gain")];
821 [o_comp_band7_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [o_comp_band7_sld floatValue]]];
824 - (IBAction)resetCompressorValues:(id)sender
826 config_PutFloat(p_intf, "compressor-rms-peak", 0.000000);
827 config_PutFloat(p_intf, "compressor-attack", 25.000000);
828 config_PutFloat(p_intf, "compressor-release", 100.000000);
829 config_PutFloat(p_intf, "compressor-threshold", -11.000000);
830 config_PutFloat(p_intf, "compressor-ratio", 8.000000);
831 config_PutFloat(p_intf, "compressor-knee", 2.500000);
832 config_PutFloat(p_intf, "compressor-makeup-gain", 7.000000);
834 audio_output_t * p_aout = getAout();
836 var_SetFloat(p_aout, "compressor-rms-peak", 0.000000);
837 var_SetFloat(p_aout, "compressor-attack", 25.000000);
838 var_SetFloat(p_aout, "compressor-release", 100.000000);
839 var_SetFloat(p_aout, "compressor-threshold", -11.000000);
840 var_SetFloat(p_aout, "compressor-ratio", 8.000000);
841 var_SetFloat(p_aout, "compressor-knee", 2.500000);
842 var_SetFloat(p_aout, "compressor-makeup-gain", 7.000000);
843 vlc_object_release(p_aout);
845 [self resetCompressor];
848 - (IBAction)comp_enable:(id)sender
850 [self setAudioFilter:"compressor" on:[sender state]];
853 - (IBAction)comp_sliderUpdated:(id)sender
855 audio_output_t * p_aout = getAout();
857 if (sender == o_comp_band1_sld)
858 value = "compressor-rms-peak";
859 else if (sender == o_comp_band2_sld)
860 value = "compressor-attack";
861 else if (sender == o_comp_band3_sld)
862 value = "compressor-release";
863 else if (sender == o_comp_band4_sld)
864 value = "compressor-threshold";
865 else if (sender == o_comp_band5_sld)
866 value = "compressor-ratio";
867 else if (sender == o_comp_band6_sld)
868 value = "compressor-knee";
869 else if (sender == o_comp_band7_sld)
870 value = "compressor-makeup-gain";
873 var_SetFloat(p_aout, value, [sender floatValue]);
874 vlc_object_release(p_aout);
876 config_PutFloat(p_intf, value, [sender floatValue]);
878 if (sender == o_comp_band1_sld)
879 [o_comp_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
880 else if (sender == o_comp_band2_sld)
881 [o_comp_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f ms", [sender floatValue]]];
882 else if (sender == o_comp_band3_sld)
883 [o_comp_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%3.1f ms", [sender floatValue]]];
884 else if (sender == o_comp_band4_sld)
885 [o_comp_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%2.1f dB", [sender floatValue]]];
886 else if (sender == o_comp_band5_sld)
887 [o_comp_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f:1", [sender floatValue]]];
888 else if (sender == o_comp_band6_sld)
889 [o_comp_band6_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [sender floatValue]]];
890 else if (sender == o_comp_band7_sld)
891 [o_comp_band7_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f dB", [sender floatValue]]];
895 #pragma mark Spatializer
896 - (void)resetSpatializer
899 psz_afilters = config_GetPsz(p_intf, "audio-filter");
901 [o_spat_enable_ckb setState: (NSInteger)strstr(psz_afilters, "spatializer") ];
905 [o_spat_enable_ckb setState: NSOffState];
907 #define setSlider(bandsld, bandfld, var) \
908 [bandsld setFloatValue: config_GetFloat(p_intf, var) * 10.]; \
909 [bandfld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [bandsld floatValue]]]
911 setSlider(o_spat_band1_sld, o_spat_band1_fld, "spatializer-roomsize");
912 setSlider(o_spat_band2_sld, o_spat_band2_fld, "spatializer-width");
913 setSlider(o_spat_band3_sld, o_spat_band3_fld, "spatializer-wet");
914 setSlider(o_spat_band4_sld, o_spat_band4_fld, "spatializer-dry");
915 setSlider(o_spat_band5_sld, o_spat_band5_fld, "spatializer-damp");
920 - (IBAction)resetSpatializerValues:(id)sender
922 config_PutFloat(p_intf, "spatializer-roomsize", .85);
923 config_PutFloat(p_intf, "spatializer-width", 1.);
924 config_PutFloat(p_intf, "spatializer-wet", .4);
925 config_PutFloat(p_intf, "spatializer-dry", .5);
926 config_PutFloat(p_intf, "spatializer-damp", .5);
928 audio_output_t * p_aout = getAout();
930 var_SetFloat(p_aout, "spatializer-roomsize", .85);
931 var_SetFloat(p_aout, "spatializer-width", 1.);
932 var_SetFloat(p_aout, "spatializer-wet", .4);
933 var_SetFloat(p_aout, "spatializer-dry", .5);
934 var_SetFloat(p_aout, "spatializer-damp", .5);
935 vlc_object_release(p_aout);
937 [self resetSpatializer];
940 - (IBAction)spat_enable:(id)sender
942 [self setAudioFilter:"spatializer" on:[sender state]];
945 - (IBAction)spat_sliderUpdated:(id)sender
947 audio_output_t * p_aout = getAout();
949 if (sender == o_spat_band1_sld)
950 value = "spatializer-roomsize";
951 else if (sender == o_spat_band2_sld)
952 value = "spatializer-width";
953 else if (sender == o_spat_band3_sld)
954 value = "spatializer-wet";
955 else if (sender == o_spat_band4_sld)
956 value = "spatializer-dry";
957 else if (sender == o_spat_band5_sld)
958 value = "spatializer-damp";
961 var_SetFloat(p_aout, value, [sender floatValue] / 10.);
962 vlc_object_release(p_aout);
964 config_PutFloat(p_intf, value, [sender floatValue] / 10.);
966 if (sender == o_spat_band1_sld)
967 [o_spat_band1_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
968 else if (sender == o_spat_band2_sld)
969 [o_spat_band2_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
970 else if (sender == o_spat_band3_sld)
971 [o_spat_band3_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
972 else if (sender == o_spat_band4_sld)
973 [o_spat_band4_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
974 else if (sender == o_spat_band5_sld)
975 [o_spat_band5_fld setStringValue:[NSString localizedStringWithFormat:@"%1.1f", [sender floatValue]]];
980 - (void)resetAudioFilters
983 psz_afilters = config_GetPsz(p_intf, "audio-filter");
985 [o_filter_headPhone_ckb setState: (NSInteger)strstr(psz_afilters, "headphone") ];
986 [o_filter_normLevel_ckb setState: (NSInteger)strstr(psz_afilters, "normvol") ];
987 [o_filter_normLevel_ckb setState: (NSInteger)strstr(psz_afilters, "karaoke") ];
990 [o_filter_headPhone_ckb setState: NSOffState];
991 [o_filter_normLevel_ckb setState: NSOffState];
992 [o_filter_karaoke_ckb setState: NSOffState];
994 [o_filter_normLevel_sld setFloatValue: config_GetFloat(p_intf, "norm-max-level")];
997 - (IBAction)filter_enableHeadPhoneVirt:(id)sender
999 [self setAudioFilter: "headphone" on:[sender state]];
1002 - (IBAction)filter_enableVolumeNorm:(id)sender
1004 [self setAudioFilter: "normvol" on:[sender state]];
1007 - (IBAction)filter_volNormSliderUpdated:(id)sender
1009 audio_output_t * p_aout= getAout();
1012 var_SetFloat(p_aout, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1013 vlc_object_release(p_aout);
1016 config_PutFloat(p_intf, "norm-max-level", [o_filter_normLevel_sld floatValue]);
1019 - (IBAction)filter_enableKaraoke:(id)sender
1021 [self setAudioFilter: "karaoke" on:[sender state]];