Cog/Audio/Chain/Node.m
Christopher Snowhill b95cb59a61 [Audio Processing] Increase thread stack size
Apparently, all these new changes with FreeSurround have pushed the
default 512KB thread stack size to the limit. And I'm not even using
stack variables, really, except for maybe the autoreleasepools.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-07-14 03:35:38 -07:00

274 lines
5.2 KiB
Objective-C

//
// Node.m
// CogNew
//
// Created by Vincent Spader on 1/4/06.
// Copyright 2006 Vincent Spader. All rights reserved.
//
#import "Node.h"
#import "BufferChain.h"
#import "Logging.h"
#import "OutputAVFoundation.h"
#import <pthread.h>
#import <mach/mach_time.h>
@implementation Node
- (id)initWithController:(id)c previous:(id)p {
self = [super init];
if(self) {
buffer = [[ChunkList alloc] initWithMaximumDuration:3.0];
semaphore = [[Semaphore alloc] init];
accessLock = [[NSLock alloc] init];
initialBufferFilled = NO;
controller = c;
endOfStream = NO;
shouldContinue = YES;
nodeChannelConfig = 0;
nodeLossless = NO;
[self setPreviousNode:p];
}
return self;
}
- (AudioStreamBasicDescription)nodeFormat {
return nodeFormat;
}
- (uint32_t)nodeChannelConfig {
return nodeChannelConfig;
}
- (BOOL)nodeLossless {
return nodeLossless;
}
- (void)writeData:(const void *)ptr amount:(size_t)amount {
[accessLock lock];
AudioChunk *chunk = [[AudioChunk alloc] init];
[chunk setFormat:nodeFormat];
if(nodeChannelConfig) {
[chunk setChannelConfig:nodeChannelConfig];
}
[chunk setLossless:nodeLossless];
[chunk assignSamples:ptr frameCount:amount / nodeFormat.mBytesPerPacket];
const double chunkDuration = [chunk duration];
double durationLeft = [buffer maxDuration] - [buffer listDuration];
while(shouldContinue == YES && chunkDuration > durationLeft) {
if(durationLeft < chunkDuration) {
if(initialBufferFilled == NO) {
initialBufferFilled = YES;
if([controller respondsToSelector:@selector(initialBufferFilled:)])
[controller performSelector:@selector(initialBufferFilled:) withObject:self];
}
}
if(durationLeft < chunkDuration || shouldReset) {
[accessLock unlock];
[semaphore wait];
[accessLock lock];
}
durationLeft = [buffer maxDuration] - [buffer listDuration];
}
[buffer addChunk:chunk];
[accessLock unlock];
}
- (void)writeChunk:(AudioChunk *)chunk {
[accessLock lock];
const double chunkDuration = [chunk duration];
double durationLeft = [buffer maxDuration] - [buffer listDuration];
while(shouldContinue == YES && chunkDuration > durationLeft) {
if(durationLeft < chunkDuration) {
if(initialBufferFilled == NO) {
initialBufferFilled = YES;
if([controller respondsToSelector:@selector(initialBufferFilled:)])
[controller performSelector:@selector(initialBufferFilled:) withObject:self];
}
}
if(durationLeft < chunkDuration || shouldReset) {
[accessLock unlock];
[semaphore wait];
[accessLock lock];
}
durationLeft = [buffer maxDuration] - [buffer listDuration];
}
[buffer addChunk:chunk];
[accessLock unlock];
}
// Should be overwriten by subclass.
- (void)process {
}
- (void)threadEntry:(id)arg {
@autoreleasepool {
[self process];
}
}
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
[accessLock lock];
BOOL ret = [[previousNode buffer] peekFormat:format channelConfig:config];
[accessLock unlock];
return ret;
}
- (AudioChunk *)readChunk:(size_t)maxFrames {
[accessLock lock];
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
endOfStream = YES;
[accessLock unlock];
return [[AudioChunk alloc] init];
}
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
[[previousNode semaphore] signal];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeSamples:maxFrames];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode semaphore] signal];
}
return ret;
}
- (AudioChunk *)readChunkAsFloat32:(size_t)maxFrames {
[accessLock lock];
if([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES) {
endOfStream = YES;
[accessLock unlock];
return [[AudioChunk alloc] init];
}
if([previousNode shouldReset] == YES) {
@autoreleasepool {
[buffer reset];
}
shouldReset = YES;
[previousNode setShouldReset:NO];
[[previousNode semaphore] signal];
}
AudioChunk *ret;
@autoreleasepool {
ret = [[previousNode buffer] removeSamplesAsFloat32:maxFrames];
}
[accessLock unlock];
if([ret frameCount]) {
[[previousNode semaphore] signal];
}
return ret;
}
- (void)launchThread {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadEntry:) object:nil];
[thread setStackSize:1024 * 1024]; // Dammit, this new code makes the nodes overflow the stack size, so let's double the stack
[thread start];
}
- (void)setPreviousNode:(id)p {
previousNode = p;
}
- (id)previousNode {
return previousNode;
}
- (BOOL)shouldContinue {
return shouldContinue;
}
- (void)setShouldContinue:(BOOL)s {
shouldContinue = s;
}
- (ChunkList *)buffer {
return buffer;
}
- (void)resetBuffer {
shouldReset = YES; // Will reset on next write.
if(previousNode == nil) {
@autoreleasepool {
[accessLock lock];
[buffer reset];
[accessLock unlock];
}
}
}
- (Semaphore *)semaphore {
return semaphore;
}
- (BOOL)endOfStream {
return endOfStream;
}
- (void)setEndOfStream:(BOOL)e {
endOfStream = e;
}
- (void)setShouldReset:(BOOL)s {
shouldReset = s;
}
- (BOOL)shouldReset {
return shouldReset;
}
// Buffering nodes should implement this
- (double)secondsBuffered {
return 0.0;
}
@end