diff --git a/Audio/Chain/OutputNode.m b/Audio/Chain/OutputNode.m index 429c398cd..abd7d9459 100644 --- a/Audio/Chain/OutputNode.m +++ b/Audio/Chain/OutputNode.m @@ -13,10 +13,8 @@ #import "DSPRubberbandNode.h" #import "DSPFSurroundNode.h" -#import "DSPHRTFNode.h" #import "DSPEqualizerNode.h" #import "VisualizationNode.h" -#import "DSPDownmixNode.h" #import "Logging.h" @@ -27,9 +25,7 @@ DSPRubberbandNode *rubberbandNode; DSPFSurroundNode *fsurroundNode; - DSPHRTFNode *hrtfNode; DSPEqualizerNode *equalizerNode; - DSPDownmixNode *downmixNode; VisualizationNode *visualizationNode; } @@ -61,13 +57,9 @@ if(!fsurroundNode) return NO; equalizerNode = [[DSPEqualizerNode alloc] initWithController:self previous:fsurroundNode latency:0.03]; if(!equalizerNode) return NO; - hrtfNode = [[DSPHRTFNode alloc] initWithController:self previous:equalizerNode latency:0.03]; - if(!hrtfNode) return NO; - downmixNode = [[DSPDownmixNode alloc] initWithController:self previous:hrtfNode latency:0.03]; - if(!downmixNode) return NO; // Approximately double the chunk size for Vis at 44100Hz - visualizationNode = [[VisualizationNode alloc] initWithController:self previous:downmixNode latency:8192.0 / 44100.0]; + visualizationNode = [[VisualizationNode alloc] initWithController:self previous:equalizerNode latency:8192.0 / 44100.0]; if(!visualizationNode) return NO; [self setPreviousNode:visualizationNode]; @@ -171,7 +163,7 @@ - (NSArray *)DSPs { if(DSPsLaunched) { - return @[rubberbandNode, fsurroundNode, equalizerNode, hrtfNode, downmixNode, visualizationNode]; + return @[rubberbandNode, fsurroundNode, equalizerNode, visualizationNode]; } else { return @[]; } @@ -288,7 +280,11 @@ formatChanged = YES; } } - if(downmixNode && output && !formatChanged) { + DSPDownmixNode *downmixNode = nil; + if(output) { + downmixNode = [output downmix]; + } + if(downmixNode && !formatChanged) { outputFormat = [output deviceFormat]; outputChannelConfig = [output deviceChannelConfig]; AudioStreamBasicDescription currentOutputFormat = [downmixNode nodeFormat]; @@ -303,7 +299,7 @@ if(converter) { [converter setOutputFormat:format]; } - if(downmixNode && output) { + if(downmixNode) { [downmixNode setOutputFormat:[output deviceFormat] withChannelConfig:[output deviceChannelConfig]]; } if(inputNode) { @@ -327,8 +323,6 @@ } previousNode = nil; visualizationNode = nil; - downmixNode = nil; - hrtfNode = nil; fsurroundNode = nil; rubberbandNode = nil; previousInput = nil; @@ -393,7 +387,7 @@ } - (id)downmix { - return downmixNode; + return [output downmix]; } @end diff --git a/Audio/Output/OutputCoreAudio.h b/Audio/Output/OutputCoreAudio.h index 6caa452cd..d3ee38e07 100644 --- a/Audio/Output/OutputCoreAudio.h +++ b/Audio/Output/OutputCoreAudio.h @@ -25,7 +25,11 @@ using std::atomic_long; #import #import -#import + +#import + +#import +#import //#define OUTPUT_LOG @@ -33,12 +37,9 @@ using std::atomic_long; @class AudioChunk; -@interface OutputCoreAudio : NSObject { +@interface OutputCoreAudio : Node { OutputNode *outputController; - dispatch_semaphore_t writeSemaphore; - dispatch_semaphore_t readSemaphore; - NSLock *outputLock; double streamTimestamp; @@ -96,7 +97,9 @@ using std::atomic_long; BOOL shouldPlayOutBuffer; - ChunkList *outputBuffer; + BOOL DSPsLaunched; + DSPHRTFNode *hrtfNode; + DSPDownmixNode *downmixNode; #ifdef OUTPUT_LOG NSFileHandle *_logFile; @@ -129,4 +132,6 @@ using std::atomic_long; - (AudioStreamBasicDescription)deviceFormat; - (uint32_t)deviceChannelConfig; +- (DSPDownmixNode *)downmix; + @end diff --git a/Audio/Output/OutputCoreAudio.m b/Audio/Output/OutputCoreAudio.m index 5664c21d6..c5a1d0a43 100644 --- a/Audio/Output/OutputCoreAudio.m +++ b/Audio/Output/OutputCoreAudio.m @@ -133,6 +133,10 @@ static void *kOutputCoreAudioContext = &kOutputCoreAudioContext; - (id)initWithController:(OutputNode *)c { self = [super init]; if(self) { + buffer = [[ChunkList alloc] initWithMaximumDuration:0.5]; + writeSemaphore = [[Semaphore alloc] init]; + readSemaphore = [[Semaphore alloc] init]; + outputController = c; volume = 1.0; outputDeviceID = -1; @@ -208,6 +212,26 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons return NO; } +- (NSArray *)DSPs { + if(DSPsLaunched) { + return @[hrtfNode, downmixNode]; + } else { + return @[]; + } +} + +- (DSPDownmixNode *)downmix { + return downmixNode; +} + +- (void)launchDSPs { + NSArray *DSPs = [self DSPs]; + + for (Node *node in DSPs) { + [node launchThread]; + } +} + - (void)threadEntry:(id)arg { @autoreleasepool { NSThread *currentThread = [NSThread currentThread]; @@ -236,14 +260,15 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons [outputLock lock]; started = NO; restarted = NO; - [outputBuffer reset]; + [buffer reset]; + [self setShouldReset:YES]; [outputLock unlock]; } if(stopping) break; - if(!cutOffInput && ![outputBuffer isFull]) { + if(!cutOffInput && ![buffer isFull]) { [self renderAndConvert]; rendered = YES; } else { @@ -556,7 +581,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons [outputController setFormat:&deviceFormat channelConfig:deviceChannelConfig]; [outputLock lock]; - [outputBuffer reset]; + [buffer reset]; + [self setShouldReset:YES]; [outputLock unlock]; if(started) { @@ -639,8 +665,9 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons size_t frameCount = 0; if(chunk && (frameCount = [chunk frameCount])) { [outputLock lock]; - [outputBuffer addChunk:chunk]; + [buffer addChunk:chunk]; [outputLock unlock]; + [readSemaphore signal]; } if(streamFormatChanged) { @@ -691,8 +718,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons while(renderedSamples < frameCount) { [refLock lock]; AudioChunk *chunk = nil; - if(_self->outputBuffer && ![_self->outputBuffer isEmpty]) { - chunk = [_self->outputBuffer removeSamples:frameCount - renderedSamples]; + if(![_self->downmixNode.buffer isEmpty]) { + chunk = [self->downmixNode.buffer removeSamples:frameCount - renderedSamples]; } [refLock unlock]; @@ -827,15 +854,19 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons visController = [VisualizationController sharedController]; + hrtfNode = [[DSPHRTFNode alloc] initWithController:self previous:self latency:0.03]; + downmixNode = [[DSPDownmixNode alloc] initWithController:self previous:hrtfNode latency:0.03]; + + [self setShouldContinue:YES]; + [self setEndOfStream:NO]; + + DSPsLaunched = YES; + [self launchDSPs]; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:kOutputCoreAudioContext]; observersapplied = YES; - outputBuffer = [[ChunkList alloc] initWithMaximumDuration:0.5]; - if(!outputBuffer) { - return NO; - } - return (err == nil); } } @@ -857,7 +888,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons } - (double)latency { - return [outputBuffer listDuration]; + return [buffer listDuration] + [[hrtfNode buffer] listDuration] + [[downmixNode buffer] listDuration]; } - (void)start { @@ -932,6 +963,14 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons usleep(5000); } } + if(DSPsLaunched) { + [self setShouldContinue:NO]; + [hrtfNode setShouldContinue:NO]; + [downmixNode setShouldContinue:NO]; + hrtfNode = nil; + downmixNode = nil; + DSPsLaunched = NO; + } #ifdef OUTPUT_LOG if(_logFile) { [_logFile closeFile]; @@ -995,9 +1034,9 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons cutOffInput = YES; [outputLock lock]; [fadedBuffersLock lock]; - FadedBuffer *buffer = [[FadedBuffer alloc] initWithBuffer:outputBuffer fadeTarget:0.0 sampleRate:deviceFormat.mSampleRate]; - outputBuffer = [[ChunkList alloc] initWithMaximumDuration:0.5]; - [fadedBuffers addObject:buffer]; + FadedBuffer *fbuffer = [[FadedBuffer alloc] initWithBuffer:buffer fadeTarget:0.0 sampleRate:deviceFormat.mSampleRate]; + buffer = [[ChunkList alloc] initWithMaximumDuration:0.5]; + [fadedBuffers addObject:fbuffer]; [fadedBuffersLock unlock]; [outputLock unlock]; cutOffInput = NO;