Visualization: Make latency animation smoother

Compensate for latency by incrementing an offset
according to animation frame rate.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2024-09-20 22:12:50 -07:00
parent 26bdd7fcc0
commit 42a7232fda
4 changed files with 36 additions and 2 deletions

View file

@ -15,12 +15,15 @@ NS_ASSUME_NONNULL_BEGIN
float *visAudio; float *visAudio;
int visAudioCursor, visAudioSize; int visAudioCursor, visAudioSize;
float *visAudioTemp; float *visAudioTemp;
uint64_t visSamplesPosted;
} }
+ (VisualizationController *)sharedController; + (VisualizationController *)sharedController;
- (void)postLatency:(double)latency; - (void)postLatency:(double)latency;
- (UInt64)samplesPosted;
- (void)postSampleRate:(double)sampleRate; - (void)postSampleRate:(double)sampleRate;
- (void)postVisPCM:(const float *)inPCM amount:(int)amount; - (void)postVisPCM:(const float *)inPCM amount:(int)amount;
- (double)readSampleRate; - (double)readSampleRate;

View file

@ -15,6 +15,7 @@ class VisualizationController : NSObject {
var visAudio: [Float] = Array(repeating: 0.0, count: 44100 * 45) var visAudio: [Float] = Array(repeating: 0.0, count: 44100 * 45)
var visAudioCursor = 0 var visAudioCursor = 0
var visAudioSize = 0 var visAudioSize = 0
var visSamplesPosted: UInt64 = 0
private static var sharedVisualizationController: VisualizationController = { private static var sharedVisualizationController: VisualizationController = {
let visualizationController = VisualizationController() let visualizationController = VisualizationController()
@ -34,6 +35,7 @@ class VisualizationController : NSObject {
for i in 0..<amount { for i in 0..<amount {
self.visAudio[i] = 0 self.visAudio[i] = 0
} }
self.visSamplesPosted = 0;
} }
} }
@ -41,6 +43,11 @@ class VisualizationController : NSObject {
func postLatency(_ latency: Double) { func postLatency(_ latency: Double) {
self.latency = latency self.latency = latency
} }
@objc
func samplesPosted() -> UInt64 {
return self.visSamplesPosted
}
@objc @objc
func postSampleRate(_ sampleRate: Double) { func postSampleRate(_ sampleRate: Double) {
@ -67,6 +74,7 @@ class VisualizationController : NSObject {
} }
self.visAudioCursor = j self.visAudioCursor = j
self.latency += Double(amount) / self.sampleRate self.latency += Double(amount) / self.sampleRate
self.visSamplesPosted += UInt64(amount);
} }
} }
@ -101,6 +109,9 @@ class VisualizationController : NSObject {
// Offset latency so the target sample is in the center of the window // Offset latency so the target sample is in the center of the window
let latencySamples = (Int)((self.latency + latencyOffset) * self.sampleRate) + 2048 let latencySamples = (Int)((self.latency + latencyOffset) * self.sampleRate) + 2048
var samplesToDo = 4096; var samplesToDo = 4096;
if(latencySamples < 0) {
return;
}
if(latencySamples < 4096) { if(latencySamples < 4096) {
// Latency can sometimes dip below this threshold // Latency can sometimes dip below this threshold
samplesToDo = latencySamples; samplesToDo = latencySamples;

View file

@ -42,6 +42,9 @@ extern NSString *CogPlaybackDidStopNotificiation;
ddb_analyzer_draw_data_t _draw_data; ddb_analyzer_draw_data_t _draw_data;
float visAudio[4096], visFFT[2048]; float visAudio[4096], visFFT[2048];
UInt64 visSamplesLastPosted;
double visLatencyOffset;
} }
@end @end
@ -234,6 +237,7 @@ extern NSString *CogPlaybackDidStopNotificiation;
- (void)timerRun:(NSTimer *)timer { - (void)timerRun:(NSTimer *)timer {
[self repaint]; [self repaint];
visLatencyOffset -= 1.0 / 60.0;
} }
- (void)colorsDidChange:(NSNotification *)notification { - (void)colorsDidChange:(NSNotification *)notification {
@ -403,7 +407,13 @@ extern NSString *CogPlaybackDidStopNotificiation;
_analyzer.view_width = self.bounds.size.width; _analyzer.view_width = self.bounds.size.width;
} }
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; UInt64 samplesPosted = [self->visController samplesPosted];
if (samplesPosted != visSamplesLastPosted) {
visSamplesLastPosted = samplesPosted;
visLatencyOffset = 0.0;
}
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:visLatencyOffset];
ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048);
ddb_analyzer_tick(&_analyzer); ddb_analyzer_tick(&_analyzer);

View file

@ -45,6 +45,9 @@ extern NSString *CogPlaybackDidStopNotificiation;
SCNVector3 cameraEulerAngles3d; SCNVector3 cameraEulerAngles3d;
float visAudio[4096], visFFT[2048]; float visAudio[4096], visFFT[2048];
UInt64 visSamplesLastPosted;
double visLatencyOffset;
} }
@end @end
@ -307,7 +310,13 @@ extern NSString *CogPlaybackDidStopNotificiation;
return; return;
} }
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:0]; UInt64 samplesPosted = [self->visController samplesPosted];
if (samplesPosted != visSamplesLastPosted) {
visSamplesLastPosted = samplesPosted;
visLatencyOffset = 0.0;
}
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0] latencyOffset:visLatencyOffset];
ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048);
ddb_analyzer_tick(&_analyzer); ddb_analyzer_tick(&_analyzer);
@ -333,6 +342,7 @@ extern NSString *CogPlaybackDidStopNotificiation;
- (void)timerRun:(NSTimer *)timer { - (void)timerRun:(NSTimer *)timer {
[self repaint]; [self repaint];
visLatencyOffset -= 1.0 / 60.0;
} }
- (void)startPlayback { - (void)startPlayback {