2022-02-13 07:04:03 +00:00
|
|
|
//
|
|
|
|
// VisualizationController.m
|
|
|
|
// CogAudio Framework
|
|
|
|
//
|
|
|
|
// Created by Christopher Snowhill on 2/12/22.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "VisualizationController.h"
|
|
|
|
#import <Accelerate/Accelerate.h>
|
|
|
|
|
|
|
|
#import "fft.h"
|
|
|
|
|
|
|
|
@implementation VisualizationController
|
|
|
|
|
|
|
|
static VisualizationController *_sharedController = nil;
|
|
|
|
|
|
|
|
+ (VisualizationController *)sharedController {
|
|
|
|
@synchronized(self) {
|
|
|
|
if(!_sharedController) {
|
|
|
|
_sharedController = [[VisualizationController alloc] init];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _sharedController;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)init {
|
|
|
|
self = [super init];
|
|
|
|
if(self) {
|
2022-06-24 06:17:31 +00:00
|
|
|
visAudio = NULL;
|
|
|
|
latency = 0;
|
2022-02-13 07:04:03 +00:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
fft_free();
|
|
|
|
}
|
|
|
|
|
2022-02-13 20:15:27 +00:00
|
|
|
- (void)postSampleRate:(double)sampleRate {
|
|
|
|
@synchronized(self) {
|
2022-06-24 06:17:31 +00:00
|
|
|
if(self->sampleRate != sampleRate) {
|
|
|
|
self->sampleRate = sampleRate;
|
2022-06-26 08:09:01 +00:00
|
|
|
int visAudioSize = (int)(sampleRate * 45.0);
|
2022-06-24 06:17:31 +00:00
|
|
|
void *visAudio = realloc(self->visAudio, visAudioSize * sizeof(float));
|
|
|
|
if(visAudio && visAudioSize) {
|
|
|
|
if(visAudioSize > self->visAudioSize) {
|
|
|
|
bzero(((float *)visAudio) + self->visAudioSize, sizeof(float) * (visAudioSize - self->visAudioSize));
|
|
|
|
}
|
|
|
|
self->visAudio = visAudio;
|
|
|
|
self->visAudioSize = visAudioSize;
|
|
|
|
visAudioCursor %= visAudioSize;
|
|
|
|
}
|
|
|
|
}
|
2022-02-13 20:15:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 05:54:55 +00:00
|
|
|
- (void)postVisPCM:(const float *)inPCM amount:(int)amount {
|
2022-02-13 07:04:03 +00:00
|
|
|
@synchronized(self) {
|
2022-06-24 06:17:31 +00:00
|
|
|
int samplesRead = 0;
|
|
|
|
while(amount > 0) {
|
|
|
|
int amountToCopy = (int)(visAudioSize - visAudioCursor);
|
|
|
|
if(amountToCopy > amount) amountToCopy = amount;
|
|
|
|
cblas_scopy(amountToCopy, inPCM + samplesRead, 1, visAudio + visAudioCursor, 1);
|
|
|
|
visAudioCursor = visAudioCursor + amountToCopy;
|
|
|
|
if(visAudioCursor >= visAudioSize) visAudioCursor -= visAudioSize;
|
|
|
|
amount -= amountToCopy;
|
|
|
|
samplesRead += amountToCopy;
|
|
|
|
}
|
2022-02-13 20:15:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-24 06:17:31 +00:00
|
|
|
- (void)postLatency:(double)latency {
|
|
|
|
self->latency = latency;
|
2022-06-26 08:09:01 +00:00
|
|
|
assert(latency < 45.0);
|
2022-06-24 06:17:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-13 20:15:27 +00:00
|
|
|
- (double)readSampleRate {
|
|
|
|
@synchronized(self) {
|
|
|
|
return sampleRate;
|
2022-02-13 07:04:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)copyVisPCM:(float *)outPCM visFFT:(float *)outFFT {
|
|
|
|
@synchronized(self) {
|
2022-06-24 06:17:31 +00:00
|
|
|
if(!sampleRate) {
|
|
|
|
bzero(outPCM, 4096 * sizeof(float));
|
|
|
|
bzero(outFFT, 2048 * sizeof(float));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int latencySamples = (int)(sampleRate * latency);
|
|
|
|
int readCursor = visAudioCursor - latencySamples;
|
|
|
|
int samples = 4096;
|
|
|
|
int samplesRead = 0;
|
|
|
|
if(readCursor < 0)
|
|
|
|
readCursor += visAudioSize;
|
|
|
|
else if(readCursor >= visAudioSize)
|
|
|
|
readCursor -= visAudioSize;
|
|
|
|
while(samples > 0) {
|
|
|
|
int samplesToRead = (int)(visAudioSize - readCursor);
|
|
|
|
if(samplesToRead > samples) samplesToRead = samples;
|
|
|
|
cblas_scopy(samplesToRead, visAudio + readCursor, 1, outPCM + samplesRead, 1);
|
|
|
|
samplesRead += samplesToRead;
|
|
|
|
readCursor += samplesToRead;
|
|
|
|
samples -= samplesToRead;
|
|
|
|
if(readCursor >= visAudioSize) readCursor -= visAudioSize;
|
|
|
|
}
|
2022-02-13 07:04:03 +00:00
|
|
|
}
|
2022-06-24 06:17:31 +00:00
|
|
|
fft_calculate(outPCM, outFFT, 2048);
|
2022-02-13 07:04:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|