Cog/Audio/Chain/Node.m
Christopher Snowhill 637ea4efe1 Core Audio output: Rewrote major portions
After all this rewriting, down or upmixing the audio is now handled with
the lowest latency possible, meaning that toggling the HRIR option now
takes effect immediately.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-02-05 03:45:02 -08:00

211 lines
3.5 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 "Logging.h"
#import "BufferChain.h"
@implementation Node
@synthesize nodeFormat;
- (id)initWithController:(id)c previous:(id)p
{
self = [super init];
if (self)
{
buffer = [[VirtualRingBuffer alloc] initWithLength:BUFFER_SIZE];
semaphore = [[Semaphore alloc] init];
initialBufferFilled = NO;
controller = c;
endOfStream = NO;
shouldContinue = YES;
[self setPreviousNode:p];
}
return self;
}
- (int)writeData:(void *)ptr amount:(int)amount
{
void *writePtr;
int amountToCopy, availOutput;
int amountLeft = amount;
while (shouldContinue == YES && amountLeft > 0)
{
BOOL wrapped;
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr bufferWrapped:&wrapped];
if (availOutput == 0) {
if (initialBufferFilled == NO) {
initialBufferFilled = YES;
if ([controller respondsToSelector:@selector(initialBufferFilled:)])
[controller performSelector:@selector(initialBufferFilled:) withObject:self];
}
}
if (availOutput == 0 || shouldReset)
{
if (availOutput)
{
// Unlock the buffer
[buffer didWriteLength:0];
}
[semaphore wait];
}
else
{
amountToCopy = availOutput;
if (amountToCopy > amountLeft)
amountToCopy = amountLeft;
memcpy(writePtr, &((char *)ptr)[amount - amountLeft], amountToCopy);
[buffer didWriteLength:amountToCopy];
amountLeft -= amountToCopy;
}
}
return (amount - amountLeft);
}
//Should be overwriten by subclass.
- (void)process
{
}
- (void)threadEntry:(id)arg
{
@autoreleasepool {
[self process];
}
}
- (int)readData:(void *)ptr amount:(int)amount
{
void *readPtr;
int amountToCopy;
int availInput;
if ([[previousNode buffer] isEmpty] && [previousNode endOfStream] == YES)
{
endOfStream = YES;
return 0;
}
availInput = [[previousNode buffer] lengthAvailableToReadReturningPointer:&readPtr];
/* if (availInput <= 0) {
DLog(@"BUFFER RAN DRY!");
}
else if (availInput < amount) {
DLog(@"BUFFER IN DANGER");
}
*/
if ([previousNode shouldReset] == YES) {
[buffer empty];
shouldReset = YES;
[previousNode setShouldReset: NO];
[[previousNode semaphore] signal];
}
amountToCopy = availInput;
if (amountToCopy > amount)
{
amountToCopy = amount;
}
memcpy(ptr, readPtr, amountToCopy);
[[previousNode buffer] didReadLength:amountToCopy];
if (amountToCopy > 0)
{
[[previousNode semaphore] signal];
}
return amountToCopy;
}
- (void)launchThread
{
[NSThread detachNewThreadSelector:@selector(threadEntry:) toTarget:self withObject:nil];
}
- (void)setPreviousNode:(id)p
{
previousNode = p;
}
- (id)previousNode
{
return previousNode;
}
- (BOOL)shouldContinue
{
return shouldContinue;
}
- (void)setShouldContinue:(BOOL)s
{
shouldContinue = s;
}
- (VirtualRingBuffer *)buffer
{
return buffer;
}
- (void)resetBuffer
{
shouldReset = YES; //Will reset on next write.
if (previousNode == nil) {
[buffer empty];
}
}
- (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