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";