// // VisualizationController.swift // CogAudio Framework // // Created by Christopher Snowhill on 6/30/22. // import Foundation @objc(VisualizationController) class VisualizationController : NSObject { var serialQueue = DispatchQueue(label: "Visualization Queue") var sampleRate = 0.0 var latency = 0.0 var visAudio: [Float] = Array(repeating: 0.0, count: 44100 * 45) var visAudioCursor = 0 var visAudioSize = 0 var visSamplesPosted: UInt64 = 0 private static var sharedVisualizationController: VisualizationController = { let visualizationController = VisualizationController() return visualizationController }() @objc class func sharedController() -> VisualizationController { return sharedVisualizationController } @objc func reset() { serialQueue.sync { self.latency = 0; let amount = self.visAudioSize for i in 0.. UInt64 { return self.visSamplesPosted } @objc func postSampleRate(_ sampleRate: Double) { serialQueue.sync { if(self.sampleRate != sampleRate) { self.sampleRate = sampleRate visAudioSize = (Int)(sampleRate * 45.0) visAudio = Array(repeating: 0.0, count: visAudioSize) visAudioCursor = 0 } } } @objc func postVisPCM(_ inPCM: UnsafePointer?, amount: Int) { serialQueue.sync { let bufferPointer = UnsafeBufferPointer(start: inPCM, count: amount) var j = self.visAudioCursor let k = self.visAudioSize if(j + amount <= k) { let endIndex = j + amount; self.visAudio.replaceSubrange(j..= k) { j = 0 } } else { let inEndIndex = k - j let remainder = amount - inEndIndex self.visAudio.replaceSubrange(j.. Double { serialQueue.sync { return self.sampleRate } } @objc func copyVisPCM(_ outPCM: UnsafeMutablePointer?, visFFT: UnsafeMutablePointer?, latencyOffset: Double) { if(self.visAudioSize == 0) { outPCM?.update(repeating: 0.0, count: 4096) visFFT?.update(repeating: 0.0, count: 2048) return } var outPCMCopy = Array(repeating: 0.0, count: 4096) serialQueue.sync { // Offset latency so the target sample is in the center of the window let latencySamples = (Int)((self.latency + latencyOffset) * self.sampleRate) + 2048 var samplesToDo = 4096; if(latencySamples < 0) { return; } if(latencySamples < 4096) { // Latency can sometimes dip below this threshold samplesToDo = latencySamples; } var j = self.visAudioCursor - latencySamples let k = self.visAudioSize if j < 0 { j += k } if(j + samplesToDo <= k) { outPCMCopy.replaceSubrange(0..