diff --git a/Audio/Output/HeadphoneFilter.h b/Audio/Output/HeadphoneFilter.h index ee1699161..26f41cd6a 100644 --- a/Audio/Output/HeadphoneFilter.h +++ b/Audio/Output/HeadphoneFilter.h @@ -12,26 +12,15 @@ #import @interface HeadphoneFilter : NSObject { - vDSP_DFT_Setup dftSetupF; - vDSP_DFT_Setup dftSetupB; - - int fftSize; - int fftSizeOver2; int bufferSize; int paddedBufferSize; int channelCount; - DSPSplitComplex signal_fft; - DSPSplitComplex input_filtered_signal_per_channel[2]; - DSPSplitComplex input_filtered_signal_totals[2]; - DSPSplitComplex *impulse_responses; - + float **mirroredImpulseResponses; + float **prevInputs; - float *left_result; - float *right_result; - - float *paddedSignal; + float *paddedSignal[2]; } + (BOOL)validateImpulseFile:(NSURL *)url; diff --git a/Audio/Output/HeadphoneFilter.mm b/Audio/Output/HeadphoneFilter.mm index 065a58255..02dfa8ff7 100644 --- a/Audio/Output/HeadphoneFilter.mm +++ b/Audio/Output/HeadphoneFilter.mm @@ -49,200 +49,59 @@ static const speakerPosition speakerPositions[18] = { { .elevation = DEGREES(+45.0), .azimuth = DEGREES(+135.0), .distance = 1.0 } }; -@interface impulseCacheObject : NSObject { -} -@property NSURL *URL; -@property int sampleCount; -@property int channelCount; -@property uint32_t channelConfig; -@property double sampleRate; -@property double targetSampleRate; -@property NSData *data; -@end - -@implementation impulseCacheObject -@synthesize URL; -@synthesize sampleCount; -@synthesize channelCount; -@synthesize channelConfig; -@synthesize sampleRate; -@synthesize targetSampleRate; -@synthesize data; -@end - -@interface impulseCache : NSObject { -} -@property NSMutableArray *cacheObjects; -+ (impulseCache *)sharedController; -- (const float *)getImpulse:(NSURL *)url sampleCount:(int *)sampleCount channelCount:(int)channelCount channelConfig:(uint32_t)channelConfig sampleRate:(double)sampleRate; -@end - -// Apparently _mm_malloc is Intel-only on newer macOS targets, so use supported posix_memalign -static void *_memalign_malloc(size_t size, size_t align) { - void *ret = NULL; - if(posix_memalign(&ret, align, size) != 0) { - return NULL; - } - return ret; -} - -@implementation impulseCache - -static impulseCache *_sharedController = nil; - -+ (impulseCache *)sharedController { - @synchronized(self) { - if(!_sharedController) { - _sharedController = [[impulseCache alloc] init]; - } - } - return _sharedController; -} - -- (id)init { - self = [super init]; - if(self) { - self.cacheObjects = [[NSMutableArray alloc] init]; - } - return self; -} - -- (impulseCacheObject *)addImpulse:(NSURL *)url sampleCount:(int)sampleCount channelCount:(int)channelCount channelConfig:(uint32_t)channelConfig originalSampleRate:(double)originalSampleRate targetSampleRate:(double)targetSampleRate impulseBuffer:(const float *)impulseBuffer { - impulseCacheObject *obj = [[impulseCacheObject alloc] init]; - - obj.URL = url; - obj.sampleCount = sampleCount; - obj.channelCount = channelCount; - obj.sampleRate = originalSampleRate; - obj.targetSampleRate = targetSampleRate; - obj.data = [NSData dataWithBytes:impulseBuffer length:(sampleCount * channelCount * sizeof(float) * 2)]; - - @synchronized(self.cacheObjects) { - [self.cacheObjects addObject:obj]; - } - - return obj; -} - -- (const float *)getImpulse:(NSURL *)url sampleCount:(int *)retSampleCount channelCount:(int)channelCount channelConfig:(uint32_t)channelConfig sampleRate:(double)sampleRate { +void getImpulse(NSURL *url, float **outImpulse, int *outSampleCount, int channelCount, uint32_t channelConfig) { BOOL impulseFound = NO; const float *impulseData = NULL; double sampleRateOfSource = 0; int sampleCount = 0; - impulseCacheObject *cacheObject = nil; - @synchronized(self.cacheObjects) { - for(impulseCacheObject *obj in self.cacheObjects) { - if([obj.URL isEqualTo:url] && - obj.targetSampleRate == sampleRate && - obj.channelCount == channelCount && - obj.channelConfig == channelConfig) { - *retSampleCount = obj.sampleCount; - return (const float *)[obj.data bytes]; - } - } - for(impulseCacheObject *obj in self.cacheObjects) { - if([obj.URL isEqualTo:url] && - obj.sampleRate == obj.targetSampleRate && - obj.channelCount == channelCount && - obj.channelConfig == channelConfig) { - impulseData = (const float *)[obj.data bytes]; - sampleCount = obj.sampleCount; - sampleRateOfSource = obj.sampleRate; - impulseFound = YES; - break; + NSString *filePath = [url path]; + + try { + std::ifstream file([filePath UTF8String], std::fstream::binary); + + if(!file.is_open()) { + throw std::logic_error("Cannot open file."); + } + + HrtfData data(file); + + file.close(); + + sampleRateOfSource = data.get_sample_rate(); + + uint32_t sampleCountExact = data.get_response_length(); + sampleCount = sampleCountExact + ((data.get_longest_delay() + 2) >> 2); + sampleCount = (sampleCount + 15) & ~15; + + *outImpulse = (float *)calloc(sizeof(float), sampleCount * channelCount * 2); + if(!*outImpulse) { + throw std::bad_alloc(); + } + float *hrtfData = *outImpulse; + + for(uint32_t i = 0; i < channelCount; ++i) { + uint32_t channelFlag = [AudioChunk extractChannelFlag:i fromConfig:channelConfig]; + uint32_t channelNumber = [AudioChunk findChannelIndex:channelFlag]; + + if(channelNumber < 18) { + const speakerPosition &speaker = speakerPositions[channelNumber]; + DirectionData hrtfLeft; + DirectionData hrtfRight; + + data.get_direction_data(speaker.elevation, speaker.azimuth, speaker.distance, hrtfLeft, hrtfRight); + + cblas_scopy(sampleCountExact, &hrtfLeft.impulse_response[0], 1, &hrtfData[((hrtfLeft.delay + 2) >> 2) + sampleCount * i * 2], 1); + cblas_scopy(sampleCountExact, &hrtfRight.impulse_response[0], 1, &hrtfData[((hrtfLeft.delay + 2) >> 2) + sampleCount * (i * 2 + 1)], 1); } } + + *outSampleCount = sampleCount; + } catch(std::exception &e) { + ALog(@"Exception caught: %s", e.what()); } - - if(!impulseFound) { - NSString *filePath = [url path]; - - try { - std::ifstream file([filePath UTF8String], std::fstream::binary); - - if(!file.is_open()) { - throw std::logic_error("Cannot open file."); - } - - HrtfData data(file); - - file.close(); - - sampleRateOfSource = data.get_sample_rate(); - - uint32_t sampleCountExact = data.get_response_length(); - sampleCount = sampleCountExact + ((data.get_longest_delay() + 2) >> 2); - - std::vector hrtfData(sampleCount * channelCount * 2, 0.0); - - for(uint32_t i = 0; i < channelCount; ++i) { - uint32_t channelFlag = [AudioChunk extractChannelFlag:i fromConfig:channelConfig]; - uint32_t channelNumber = [AudioChunk findChannelIndex:channelFlag]; - - if(channelNumber < 18) { - const speakerPosition &speaker = speakerPositions[channelNumber]; - DirectionData hrtfLeft; - DirectionData hrtfRight; - - data.get_direction_data(speaker.elevation, speaker.azimuth, speaker.distance, hrtfLeft, hrtfRight); - - cblas_scopy(sampleCountExact, &hrtfLeft.impulse_response[0], 1, &hrtfData[((hrtfLeft.delay + 2) >> 2) * channelCount * 2 + i * 2], channelCount * 2); - cblas_scopy(sampleCountExact, &hrtfRight.impulse_response[0], 1, &hrtfData[((hrtfLeft.delay + 2) >> 2) * channelCount * 2 + i * 2 + 1], channelCount * 2); - } - } - - cacheObject = [self addImpulse:url sampleCount:sampleCount channelCount:channelCount channelConfig:channelConfig originalSampleRate:sampleRateOfSource targetSampleRate:sampleRateOfSource impulseBuffer:&hrtfData[0]]; - - impulseData = (const float *)[cacheObject.data bytes]; - } catch(std::exception &e) { - ALog(@"Exception caught: %s", e.what()); - return nil; - } - } - - if(sampleRateOfSource != sampleRate) { - double sampleRatio = sampleRate / sampleRateOfSource; - int resampledCount = (int)ceil((double)sampleCount * sampleRatio); - - void *rsstate = rsstate_new(channelCount * 2, sampleRateOfSource, sampleRate); - - float *resampledImpulse = (float *)_memalign_malloc(resampledCount * sizeof(float) * channelCount * 2, 16); - if(!resampledImpulse) { - rsstate_delete(rsstate); - return nil; - } - - size_t inputDone = 0; - size_t outputDone = 0; - - outputDone = rsstate_resample(rsstate, impulseData, sampleCount, &inputDone, resampledImpulse, resampledCount); - - while(outputDone < resampledCount) { - outputDone += rsstate_flush(rsstate, resampledImpulse + outputDone * channelCount * 2, resampledCount - outputDone); - } - - rsstate_delete(rsstate); - - sampleCount = (int)outputDone; - - // Normalize resampled impulse by sample ratio - float fSampleRatio = (float)sampleRatio; - vDSP_vsdiv(resampledImpulse, 1, &fSampleRatio, resampledImpulse, 1, sampleCount * channelCount * 2); - - cacheObject = [self addImpulse:url sampleCount:sampleCount channelCount:channelCount channelConfig:channelConfig originalSampleRate:sampleRateOfSource targetSampleRate:sampleRate impulseBuffer:resampledImpulse]; - - free(resampledImpulse); - - impulseData = (const float *)[cacheObject.data bytes]; - } - - *retSampleCount = sampleCount; - return impulseData; } -@end - @implementation HeadphoneFilter + (BOOL)validateImpulseFile:(NSURL *)url { @@ -270,132 +129,42 @@ static impulseCache *_sharedController = nil; self = [super init]; if(self) { + float *impulseBuffer = NULL; int sampleCount = 0; - const float *impulseBuffer = [[impulseCache sharedController] getImpulse:url sampleCount:&sampleCount channelCount:channels channelConfig:config sampleRate:sampleRate]; + getImpulse(url, &impulseBuffer, &sampleCount, channels, config); if(!impulseBuffer) { return nil; } channelCount = channels; - bufferSize = 512; - fftSize = sampleCount + bufferSize; - - int pow = 1; - while(fftSize > 2) { - pow++; - fftSize /= 2; - } - fftSize = 2 << pow; - - float *deinterleavedImpulseBuffer = (float *)_memalign_malloc(fftSize * sizeof(float) * channelCount * 2, 16); - if(!deinterleavedImpulseBuffer) { + mirroredImpulseResponses = (float **)calloc(sizeof(float *), channelCount * 2); + if(!mirroredImpulseResponses) { + free(impulseBuffer); return nil; } - for(int i = 0; i < channelCount; ++i) { - cblas_scopy(sampleCount, impulseBuffer + i * 2, (int)channelCount * 2, deinterleavedImpulseBuffer + i * fftSize * 2, 1); - vDSP_vclr(deinterleavedImpulseBuffer + i * fftSize * 2 + sampleCount, 1, fftSize - sampleCount); - cblas_scopy(sampleCount, impulseBuffer + i * 2 + 1, (int)channelCount * 2, deinterleavedImpulseBuffer + i * fftSize * 2 + fftSize, 1); - vDSP_vclr(deinterleavedImpulseBuffer + i * fftSize * 2 + fftSize + sampleCount, 1, fftSize - sampleCount); + for(int i = 0; i < channelCount * 2; ++i) { + mirroredImpulseResponses[i] = &impulseBuffer[sampleCount * i]; + vDSP_vrvrs(mirroredImpulseResponses[i], 1, sampleCount); } - paddedBufferSize = fftSize; - fftSizeOver2 = (fftSize + 1) / 2; - const int fftSizeOver2Plus1 = fftSizeOver2 + 1; // DFT float overwrites plus one, double doesn't + paddedBufferSize = sampleCount; - dftSetupF = vDSP_DFT_zrop_CreateSetup(nil, fftSize, vDSP_DFT_FORWARD); - dftSetupB = vDSP_DFT_zrop_CreateSetup(nil, fftSize, vDSP_DFT_INVERSE); - if(!dftSetupF || !dftSetupB) { - free(deinterleavedImpulseBuffer); + paddedSignal[0] = (float *)calloc(sizeof(float), paddedBufferSize * 2); + if(!paddedSignal[0]) { return nil; } - - paddedSignal = (float *)_memalign_malloc(sizeof(float) * paddedBufferSize, 16); - if(!paddedSignal) { - free(deinterleavedImpulseBuffer); - return nil; - } - - signal_fft.realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - signal_fft.imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - if(!signal_fft.realp || !signal_fft.imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - input_filtered_signal_per_channel[0].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - input_filtered_signal_per_channel[0].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - if(!input_filtered_signal_per_channel[0].realp || - !input_filtered_signal_per_channel[0].imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - input_filtered_signal_per_channel[1].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - input_filtered_signal_per_channel[1].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - if(!input_filtered_signal_per_channel[1].realp || - !input_filtered_signal_per_channel[1].imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - input_filtered_signal_totals[0].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - input_filtered_signal_totals[0].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - if(!input_filtered_signal_totals[0].realp || - !input_filtered_signal_totals[0].imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - input_filtered_signal_totals[1].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - input_filtered_signal_totals[1].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - if(!input_filtered_signal_totals[1].realp || - !input_filtered_signal_totals[1].imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - impulse_responses = (DSPSplitComplex *)calloc(sizeof(DSPSplitComplex), channels * 2); - if(!impulse_responses) { - free(deinterleavedImpulseBuffer); - return nil; - } - - for(int i = 0; i < channels; ++i) { - impulse_responses[i * 2 + 0].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - impulse_responses[i * 2 + 0].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - impulse_responses[i * 2 + 1].realp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - impulse_responses[i * 2 + 1].imagp = (float *)_memalign_malloc(sizeof(float) * fftSizeOver2Plus1, 16); - - if(!impulse_responses[i * 2 + 0].realp || !impulse_responses[i * 2 + 0].imagp || - !impulse_responses[i * 2 + 1].realp || !impulse_responses[i * 2 + 1].imagp) { - free(deinterleavedImpulseBuffer); - return nil; - } - - vDSP_ctoz((DSPComplex *)(deinterleavedImpulseBuffer + i * fftSize * 2), 2, &impulse_responses[i * 2 + 0], 1, fftSizeOver2); - vDSP_ctoz((DSPComplex *)(deinterleavedImpulseBuffer + i * fftSize * 2 + fftSize), 2, &impulse_responses[i * 2 + 1], 1, fftSizeOver2); - - vDSP_DFT_Execute(dftSetupF, impulse_responses[i * 2 + 0].realp, impulse_responses[i * 2 + 0].imagp, impulse_responses[i * 2 + 0].realp, impulse_responses[i * 2 + 0].imagp); - vDSP_DFT_Execute(dftSetupF, impulse_responses[i * 2 + 1].realp, impulse_responses[i * 2 + 1].imagp, impulse_responses[i * 2 + 1].realp, impulse_responses[i * 2 + 1].imagp); - } - - free(deinterleavedImpulseBuffer); - - left_result = (float *)_memalign_malloc(sizeof(float) * fftSize, 16); - right_result = (float *)_memalign_malloc(sizeof(float) * fftSize, 16); - if(!left_result || !right_result) - return nil; + paddedSignal[1] = paddedSignal[0] + paddedBufferSize; prevInputs = (float **)calloc(channels, sizeof(float *)); if(!prevInputs) return nil; - for(int i = 0; i < channels; ++i) { - prevInputs[i] = (float *)_memalign_malloc(sizeof(float) * fftSize, 16); - if(!prevInputs[i]) - return nil; - vDSP_vclr(prevInputs[i], 1, fftSize); + prevInputs[0] = (float *)calloc(sizeof(float), sampleCount * channelCount); + if(!prevInputs[0]) + return nil; + for(int i = 1; i < channels; ++i) { + prevInputs[i] = prevInputs[i - 1] + sampleCount; } } @@ -403,113 +172,52 @@ static impulseCache *_sharedController = nil; } - (void)dealloc { - if(dftSetupF) vDSP_DFT_DestroySetup(dftSetupF); - if(dftSetupB) vDSP_DFT_DestroySetup(dftSetupB); - - free(paddedSignal); - - free(signal_fft.realp); - free(signal_fft.imagp); - - free(input_filtered_signal_per_channel[0].realp); - free(input_filtered_signal_per_channel[0].imagp); - free(input_filtered_signal_per_channel[1].realp); - free(input_filtered_signal_per_channel[1].imagp); - - free(input_filtered_signal_totals[0].realp); - free(input_filtered_signal_totals[0].imagp); - free(input_filtered_signal_totals[1].realp); - free(input_filtered_signal_totals[1].imagp); - - if(impulse_responses) { - for(int i = 0; i < channelCount * 2; ++i) { - free(impulse_responses[i].realp); - free(impulse_responses[i].imagp); - } - free(impulse_responses); + if(paddedSignal[0]) { + free(paddedSignal[0]); } - free(left_result); - free(right_result); - if(prevInputs) { - for(int i = 0; i < channelCount; ++i) { - free(prevInputs[i]); + if(prevInputs[0]) { + free(prevInputs[0]); } free(prevInputs); } + + if(mirroredImpulseResponses) { + if(mirroredImpulseResponses[0]) { + free(mirroredImpulseResponses[0]); + } + free(mirroredImpulseResponses); + } } - (void)process:(const float *)inBuffer sampleCount:(int)count toBuffer:(float *)outBuffer { - const float scale = 1.0 / (4.0 * (float)fftSize); - + int sampleCount = paddedBufferSize; while(count > 0) { - const int countToDo = (count > bufferSize) ? bufferSize : count; - const int prevToDo = fftSize - countToDo; - - vDSP_vclr(input_filtered_signal_totals[0].realp, 1, fftSizeOver2); - vDSP_vclr(input_filtered_signal_totals[0].imagp, 1, fftSizeOver2); - vDSP_vclr(input_filtered_signal_totals[1].realp, 1, fftSizeOver2); - vDSP_vclr(input_filtered_signal_totals[1].imagp, 1, fftSizeOver2); - + float left = 0, right = 0; for(int i = 0; i < channelCount; ++i) { - cblas_scopy((int)prevToDo, prevInputs[i] + countToDo, 1, paddedSignal, 1); - cblas_scopy((int)countToDo, inBuffer + i, (int)channelCount, paddedSignal + prevToDo, 1); - cblas_scopy((int)fftSize, paddedSignal, 1, prevInputs[i], 1); + float thisleft, thisright; + vDSP_vmul(prevInputs[i], 1, mirroredImpulseResponses[i * 2], 1, paddedSignal[0], 1, sampleCount); + vDSP_vmul(prevInputs[i], 1, mirroredImpulseResponses[i * 2 + 1], 1, paddedSignal[1], 1, sampleCount); + vDSP_sve(paddedSignal[0], 1, &thisleft, sampleCount); + vDSP_sve(paddedSignal[1], 1, &thisright, sampleCount); + left += thisleft; + right += thisright; - vDSP_ctoz((DSPComplex *)paddedSignal, 2, &signal_fft, 1, fftSizeOver2); - - vDSP_DFT_Execute(dftSetupF, signal_fft.realp, signal_fft.imagp, signal_fft.realp, signal_fft.imagp); - - // One channel forward, then multiply and back twice - - float preserveIRNyq = impulse_responses[i * 2 + 0].imagp[0]; - float preserveSigNyq = signal_fft.imagp[0]; - impulse_responses[i * 2 + 0].imagp[0] = 0; - signal_fft.imagp[0] = 0; - - vDSP_zvmul(&signal_fft, 1, &impulse_responses[i * 2 + 0], 1, &input_filtered_signal_per_channel[0], 1, fftSizeOver2, 1); - - input_filtered_signal_per_channel[0].imagp[0] = preserveIRNyq * preserveSigNyq; - impulse_responses[i * 2 + 0].imagp[0] = preserveIRNyq; - - preserveIRNyq = impulse_responses[i * 2 + 1].imagp[0]; - impulse_responses[i * 2 + 1].imagp[0] = 0; - - vDSP_zvmul(&signal_fft, 1, &impulse_responses[i * 2 + 1], 1, &input_filtered_signal_per_channel[1], 1, fftSizeOver2, 1); - - input_filtered_signal_per_channel[1].imagp[0] = preserveIRNyq * preserveSigNyq; - impulse_responses[i * 2 + 1].imagp[0] = preserveIRNyq; - - vDSP_zvadd(&input_filtered_signal_totals[0], 1, &input_filtered_signal_per_channel[0], 1, &input_filtered_signal_totals[0], 1, fftSizeOver2); - vDSP_zvadd(&input_filtered_signal_totals[1], 1, &input_filtered_signal_per_channel[1], 1, &input_filtered_signal_totals[1], 1, fftSizeOver2); + memmove(prevInputs[i], prevInputs[i] + 1, sizeof(float) * (sampleCount - 1)); + prevInputs[i][sampleCount - 1] = *inBuffer++; } - - vDSP_DFT_Execute(dftSetupB, input_filtered_signal_totals[0].realp, input_filtered_signal_totals[0].imagp, input_filtered_signal_totals[0].realp, input_filtered_signal_totals[0].imagp); - vDSP_DFT_Execute(dftSetupB, input_filtered_signal_totals[1].realp, input_filtered_signal_totals[1].imagp, input_filtered_signal_totals[1].realp, input_filtered_signal_totals[1].imagp); - - vDSP_ztoc(&input_filtered_signal_totals[0], 1, (DSPComplex *)left_result, 2, fftSizeOver2); - vDSP_ztoc(&input_filtered_signal_totals[1], 1, (DSPComplex *)right_result, 2, fftSizeOver2); - - float *left_ptr = left_result + prevToDo; - float *right_ptr = right_result + prevToDo; - - vDSP_vsmul(left_ptr, 1, &scale, left_ptr, 1, countToDo); - vDSP_vsmul(right_ptr, 1, &scale, right_ptr, 1, countToDo); - - cblas_scopy((int)countToDo, left_ptr, 1, outBuffer + 0, 2); - cblas_scopy((int)countToDo, right_ptr, 1, outBuffer + 1, 2); - - inBuffer += countToDo * channelCount; - outBuffer += countToDo * 2; - - count -= countToDo; + + outBuffer[0] = left; + outBuffer[1] = right; + outBuffer += 2; + --count; } } - (void)reset { for(int i = 0; i < channelCount; ++i) { - vDSP_vclr(prevInputs[i], 1, fftSize); + vDSP_vclr(prevInputs[i], 1, paddedBufferSize); } } diff --git a/Preferences/Preferences/Base.lproj/Preferences.xib b/Preferences/Preferences/Base.lproj/Preferences.xib index c9670f9f4..bb5201128 100644 --- a/Preferences/Preferences/Base.lproj/Preferences.xib +++ b/Preferences/Preferences/Base.lproj/Preferences.xib @@ -1,8 +1,8 @@ - + - + @@ -36,7 +36,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -146,7 +146,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -198,7 +198,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -328,7 +328,7 @@ - + @@ -426,7 +426,7 @@ - + @@ -465,7 +465,7 @@ - + @@ -500,7 +500,7 @@ - + @@ -647,7 +647,7 @@ - + @@ -668,7 +668,7 @@ - + @@ -695,7 +695,7 @@ - + @@ -704,7 +704,7 @@ - + @@ -721,7 +721,7 @@ - + @@ -751,7 +751,7 @@ - + @@ -781,7 +781,7 @@ - + @@ -811,7 +811,7 @@ - + @@ -820,7 +820,7 @@ - + @@ -836,7 +836,7 @@ - + @@ -845,7 +845,7 @@ - + @@ -854,7 +854,7 @@ - + @@ -870,7 +870,7 @@ - + @@ -879,7 +879,7 @@ - + @@ -888,7 +888,7 @@ - + @@ -901,7 +901,7 @@ - + @@ -910,7 +910,7 @@ - + @@ -919,7 +919,7 @@ - + @@ -932,7 +932,7 @@ - + diff --git a/Preferences/Preferences/en.lproj/Preferences.strings b/Preferences/Preferences/en.lproj/Preferences.strings index 7f5a770a7..4fcf03f27 100644 --- a/Preferences/Preferences/en.lproj/Preferences.strings +++ b/Preferences/Preferences/en.lproj/Preferences.strings @@ -230,8 +230,8 @@ /* Class = "NSButtonCell"; title = "Use 3D rendered spectrum"; ObjectID = "NMg-TO-amV"; */ "NMg-TO-amV.title" = "Use 3D rendered spectrum"; -/* Class = "NSButtonCell"; title = "Enable HRTF filter (Not needed with AirPods or Beats)"; ObjectID = "NGx-0c-WVR"; */ -"NGx-0c-WVR.title" = "Enable HRTF filter (Not needed with AirPods or Beats)"; +/* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ +"NGx-0c-WVR.title" = "Enable HRTF filter"; /* Class = "NSButtonCell"; title = "Enable FreeSurround stereo to surround upmixing"; ObjectID = "F0i-UK-6Nu"; */ "F0i-UK-6Nu.title" = "Enable FreeSurround stereo to surround upmixing"; diff --git a/Preferences/Preferences/es.lproj/Preferences.strings b/Preferences/Preferences/es.lproj/Preferences.strings index 60b0ece21..cd97ffa9e 100644 --- a/Preferences/Preferences/es.lproj/Preferences.strings +++ b/Preferences/Preferences/es.lproj/Preferences.strings @@ -226,8 +226,8 @@ /* Class = "NSButtonCell"; title = "Use 3D rendered spectrum"; ObjectID = "NMg-TO-amV"; */ "NMg-TO-amV.title" = "Usar analizador en tres dimensiones"; -/* Class = "NSButtonCell"; title = "Enable HRTF filter (Not needed with AirPods or Beats)"; ObjectID = "NGx-0c-WVR"; */ -"NGx-0c-WVR.title" = "Activar filtro HRTF (no es necesario con AirPods o Beats)"; +/* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ +"NGx-0c-WVR.title" = "Activar filtro HRTF"; /* Class = "NSButtonCell"; title = "Automatically check for updates on startup"; ObjectID = "207"; */ "207.title" = "Buscar actualizaciones al abrir"; diff --git a/Preferences/Preferences/ru.lproj/Preferences.strings b/Preferences/Preferences/ru.lproj/Preferences.strings index dec16b3ce..f0921a623 100644 --- a/Preferences/Preferences/ru.lproj/Preferences.strings +++ b/Preferences/Preferences/ru.lproj/Preferences.strings @@ -191,8 +191,8 @@ /* Class = "NSButtonCell"; title = "Use 3D rendered spectrum"; ObjectID = "NMg-TO-amV"; */ "NMg-TO-amV.title" = "Использовать 3D-рендеринг спектра"; -/* Class = "NSButtonCell"; title = "Enable HRTF filter (Not needed with AirPods or Beats)"; ObjectID = "NGx-0c-WVR"; */ -"NGx-0c-WVR.title" = "Включить фильтр HRTF (не требуется с AirPods или Beats)"; +/* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ +"NGx-0c-WVR.title" = "Включить фильтр HRTF"; /* Class = "NSButtonCell"; title = "Enable FreeSurround stereo to surround upmixing"; ObjectID = "F0i-UK-6Nu"; */ "F0i-UK-6Nu.title" = "Включить FreeSurround апмикс стерео в объемный звук"; diff --git a/Preferences/Preferences/tr.lproj/Preferences.strings b/Preferences/Preferences/tr.lproj/Preferences.strings index 6950ab802..8a09d3781 100644 --- a/Preferences/Preferences/tr.lproj/Preferences.strings +++ b/Preferences/Preferences/tr.lproj/Preferences.strings @@ -128,8 +128,8 @@ /* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "LwT-Qb-47r"; */ "LwT-Qb-47r.title" = "Tablo Görünümü Hücresi"; -/* Class = "NSButtonCell"; title = "Enable HRTF filter (Not needed with AirPods or Beats)"; ObjectID = "NGx-0c-WVR"; */ -"NGx-0c-WVR.title" = "HRTF filtresini etkinleştir (Airpods veya Beats ile gerekli değildir)"; +/* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ +"NGx-0c-WVR.title" = "HRTF filtresini etkinleştir"; /* Class = "NSButtonCell"; title = "Use 3D rendered spectrum"; ObjectID = "NMg-TO-amV"; */ "NMg-TO-amV.title" = "3D işlenmiş spektrum kullanın";