diff --git a/Application/PlaybackController.m b/Application/PlaybackController.m index 55359c326..c7d920962 100644 --- a/Application/PlaybackController.m +++ b/Application/PlaybackController.m @@ -98,7 +98,9 @@ NSString *CogPlaybackDidStopNotificiation = @"CogPlaybackDidStopNotificiation"; @"GraphicEQpreset": @(-1), @"GraphicEQtrackgenre": @(NO), @"volumeLimit": @(YES), - @"headphoneVirtualization": @(NO) }; + @"enableHrtf": @(NO), + @"enableHeadTracking": @(NO) + }; [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary]; } diff --git a/Audio/Output/OutputCoreAudio.h b/Audio/Output/OutputCoreAudio.h index d5a89a72e..5e2978573 100644 --- a/Audio/Output/OutputCoreAudio.h +++ b/Audio/Output/OutputCoreAudio.h @@ -75,6 +75,9 @@ using std::atomic_long; BOOL eqEnabled; BOOL eqInitialized; + BOOL enableHeadTracking; + BOOL lastEnableHeadTracking; + BOOL streamFormatStarted; BOOL streamFormatChanged; @@ -84,6 +87,7 @@ using std::atomic_long; BOOL currentdevicelistenerapplied; BOOL devicealivelistenerapplied; BOOL observersapplied; + BOOL htlistenerapplied; BOOL outputdevicechanged; float volume; @@ -182,6 +186,7 @@ using std::atomic_long; - (void)sustainHDCD; - (void)reportMotion:(simd_float4x4)matrix; +- (void)resetReferencePosition; - (void)setPitch:(double)p; - (void)setTempo:(double)t; diff --git a/Audio/Output/OutputCoreAudio.m b/Audio/Output/OutputCoreAudio.m index a0ff78179..fcda82ebc 100644 --- a/Audio/Output/OutputCoreAudio.m +++ b/Audio/Output/OutputCoreAudio.m @@ -31,6 +31,8 @@ extern void scale_by_volume(float *buffer, size_t count, float volume); static NSString *CogPlaybackDidBeginNotificiation = @"CogPlaybackDidBeginNotificiation"; +static NSString *CogPlaybackDidResetHeadTracking = @"CogPlaybackDigResetHeadTracking"; + #define tts ((RubberBandState)ts) simd_float4x4 convertMatrix(CMRotationMatrix r) { @@ -394,8 +396,10 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons } else if([keyPath isEqualToString:@"values.eqPreamp"]) { float preamp = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] floatForKey:@"eqPreamp"]; eqPreamp = pow(10.0, preamp / 20.0); - } else if([keyPath isEqualToString:@"values.enableHrtf"]) { + } else if([keyPath isEqualToString:@"values.enableHrtf"] || + [keyPath isEqualToString:@"values.enableHeadTracking"]) { enableHrtf = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"enableHrtf"]; + enableHeadTracking = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"enableHeadTracking"]; if(streamFormatStarted) resetStreamFormat = YES; } else if([keyPath isEqualToString:@"values.enableFSurround"]) { @@ -793,12 +797,27 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons rotationMatrixUpdated = NO; simd_float4x4 matrix; - if(!referenceMatrixSet) { + if(!referenceMatrixSet || !enableHeadTracking) { + referenceMatrixSet = NO; matrix = matrix_identity_float4x4; self->referenceMatrix = matrix; - registerMotionListener(self); + if(enableHeadTracking) { + lastEnableHeadTracking = YES; + registerMotionListener(self); + } else if(lastEnableHeadTracking) { + lastEnableHeadTracking = NO; + unregisterMotionListener(); + } } else { - matrix = simd_mul(rotationMatrix, referenceMatrix); + simd_float4x4 mirrorTransform = { + simd_make_float4(-1.0, 0.0, 0.0, 0.0), + simd_make_float4(0.0, 1.0, 0.0, 0.0), + simd_make_float4(0.0, 0.0, 1.0, 0.0), + simd_make_float4(0.0, 0.0, 0.0, 1.0) + }; + + matrix = simd_mul(mirrorTransform, rotationMatrix); + matrix = simd_mul(matrix, referenceMatrix); } [outputLock lock]; @@ -808,7 +827,10 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons channels = 2; channelConfig = AudioChannelSideLeft | AudioChannelSideRight; } else { - unregisterMotionListener(); + if(lastEnableHeadTracking) { + lastEnableHeadTracking = NO; + unregisterMotionListener(); + } referenceMatrixSet = NO; [outputLock lock]; @@ -976,7 +998,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons int simpleSpeedInput = samplesRendered; int simpleSpeedRendered = 0; int channels = realStreamFormat.mChannelsPerFrame; - size_t max_block_len = blockSize; + //size_t max_block_len = blockSize; if (fabs(pitch - lastPitch) > 1e-5 || fabs(tempo - lastTempo) > 1e-5) { @@ -1309,9 +1331,13 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.eqPreamp" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableHrtf" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kOutputCoreAudioContext]; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableHeadTracking" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.enableFSurround" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kOutputCoreAudioContext]; observersapplied = YES; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetReferencePosition:) name:CogPlaybackDidResetHeadTracking object:nil]; + htlistenerapplied = YES; + bzero(&timeStamp, sizeof(timeStamp)); timeStamp.mFlags = kAudioTimeStampSampleTimeValid; @@ -1381,14 +1407,20 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons } @synchronized(self) { stopInvoked = YES; - if(hrtf) { + if(hrtf && lastEnableHeadTracking) { + lastEnableHeadTracking = NO; unregisterMotionListener(); } + if(htlistenerapplied) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:CogPlaybackDidResetHeadTracking object:nil]; + htlistenerapplied = NO; + } if(observersapplied) { [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable" context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.eqPreamp" context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableHrtf" context:kOutputCoreAudioContext]; + [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableHeadTracking" context:kOutputCoreAudioContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.enableFSurround" context:kOutputCoreAudioContext]; observersapplied = NO; } @@ -1505,4 +1537,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons rotationMatrixUpdated = YES; } +- (void)resetReferencePosition:(NSNotification *)notification { + referenceMatrixSet = NO; +} + @end diff --git a/Preferences/Preferences/Base.lproj/Preferences.xib b/Preferences/Preferences/Base.lproj/Preferences.xib index e16aad2c9..2cbef3953 100644 --- a/Preferences/Preferences/Base.lproj/Preferences.xib +++ b/Preferences/Preferences/Base.lproj/Preferences.xib @@ -251,6 +251,8 @@ + + @@ -293,7 +295,7 @@ + + diff --git a/Preferences/Preferences/OutputPane.h b/Preferences/Preferences/OutputPane.h index 2f55eff0a..fe856031b 100644 --- a/Preferences/Preferences/OutputPane.h +++ b/Preferences/Preferences/OutputPane.h @@ -12,8 +12,11 @@ @interface OutputPane : GeneralPreferencePane { IBOutlet OutputsArrayController *outputDevices; + IBOutlet NSButton *headTracking; + IBOutlet NSButton *headRecenter; } - (IBAction)takeDeviceID:(id)sender; +- (IBAction)resetHeadTracking:(id)sender; @end diff --git a/Preferences/Preferences/OutputPane.m b/Preferences/Preferences/OutputPane.m index 5b0a82e15..58885aa93 100644 --- a/Preferences/Preferences/OutputPane.m +++ b/Preferences/Preferences/OutputPane.m @@ -8,6 +8,8 @@ #import "OutputPane.h" +static NSString *CogPlaybackDidResetHeadTracking = @"CogPlaybackDigResetHeadTracking"; + @implementation OutputPane - (NSString *)title { @@ -15,6 +17,12 @@ } - (NSImage *)icon { + if(@available(macOS 14.0, *)) { + /* do nothing */ + } else { + [headTracking setHidden:YES]; + [headRecenter setHidden:YES]; + } if(@available(macOS 11.0, *)) return [NSImage imageWithSystemSymbolName:@"hifispeaker.2.fill" accessibilityDescription:nil]; return [[NSImage alloc] initWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForImageResource:@"output"]]; @@ -25,4 +33,8 @@ [[NSUserDefaults standardUserDefaults] setObject:device forKey:@"outputDevice"]; } +- (IBAction)resetHeadTracking:(id)sender { + [[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidResetHeadTracking object:nil]; +} + @end diff --git a/Preferences/Preferences/en.lproj/Preferences.strings b/Preferences/Preferences/en.lproj/Preferences.strings index 6d6121ef6..8b8ec3222 100644 --- a/Preferences/Preferences/en.lproj/Preferences.strings +++ b/Preferences/Preferences/en.lproj/Preferences.strings @@ -233,6 +233,12 @@ /* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ "NGx-0c-WVR.title" = "Enable HRTF filter"; +/* Class = "NSButtonCell"; title = "Head Tracking"; ObjectID = "Lpr-85-geO"; */ +"Lpr-85-geO.title" = "Head Tracking"; + +/* Class = "NSButtonCell"; title = "Recenter"; ObjectID = "aQP-kn-fMB"; */ +"aQP-kn-fMB.title" = "Recenter"; + /* 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 537009622..afc069cb8 100644 --- a/Preferences/Preferences/es.lproj/Preferences.strings +++ b/Preferences/Preferences/es.lproj/Preferences.strings @@ -229,6 +229,12 @@ /* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ "NGx-0c-WVR.title" = "Activar filtro HRTF"; +/* Class = "NSButtonCell"; title = "Head Tracking"; ObjectID = "Lpr-85-geO"; */ +"Lpr-85-geO.title" = "Seguimiento de cabeza"; + +/* Class = "NSButtonCell"; title = "Recenter"; ObjectID = "aQP-kn-fMB"; */ +"aQP-kn-fMB.title" = "Recalibrar"; + /* 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 52c437142..c3e92d998 100644 --- a/Preferences/Preferences/ru.lproj/Preferences.strings +++ b/Preferences/Preferences/ru.lproj/Preferences.strings @@ -194,6 +194,12 @@ /* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ "NGx-0c-WVR.title" = "Включить фильтр HRTF"; +/* Class = "NSButtonCell"; title = "Head Tracking"; ObjectID = "Lpr-85-geO"; */ +"Lpr-85-geO.title" = "Трекинг головы"; + +/* Class = "NSButtonCell"; title = "Recenter"; ObjectID = "aQP-kn-fMB"; */ +"aQP-kn-fMB.title" = "Перецентрировать"; + /* 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 3b0c10078..7c9470609 100644 --- a/Preferences/Preferences/tr.lproj/Preferences.strings +++ b/Preferences/Preferences/tr.lproj/Preferences.strings @@ -131,6 +131,12 @@ /* Class = "NSButtonCell"; title = "Enable HRTF filter"; ObjectID = "NGx-0c-WVR"; */ "NGx-0c-WVR.title" = "HRTF filtresini etkinleştir"; +/* Class = "NSButtonCell"; title = "Head Tracking"; ObjectID = "Lpr-85-geO"; */ +"Lpr-85-geO.title" = "Kafa Takibi"; + +/* Class = "NSButtonCell"; title = "Recenter"; ObjectID = "aQP-kn-fMB"; */ +"aQP-kn-fMB.title" = "Yeniden Merkeze Getir"; + /* Class = "NSButtonCell"; title = "Use 3D rendered spectrum"; ObjectID = "NMg-TO-amV"; */ "NMg-TO-amV.title" = "3D işlenmiş spektrum kullanın";