cog/Audio/Chain/OutputNode.m

210 lines
4.0 KiB
Objective-C

//
// OutputNode.m
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
//
#import "OutputNode.h"
#import "OutputCoreAudio.h"
#import "AudioPlayer.h"
#import "BufferChain.h"
#import "Logging.h"
@implementation OutputNode
- (void)setup
{
amountPlayed = 0.0;
sampleRatio = 0.0;
paused = YES;
started = NO;
formatSetup = NO;
formatChanged = NO;
output = [[OutputCoreAudio alloc] initWithController:self];
[output setup];
}
- (void)seek:(double)time
{
// [output pause];
[self resetBuffer];
amountPlayed = time;
}
- (void)process
{
paused = NO;
[output start];
}
- (void)pause
{
paused = YES;
[output pause];
}
- (void)resume
{
paused = NO;
[output resume];
}
- (void)incrementAmountPlayed:(long)count
{
amountPlayed += (double)count * sampleRatio;
}
- (void)resetAmountPlayed
{
amountPlayed = 0;
}
- (void)endOfInputPlayed
{
[controller endOfInputPlayed];
}
- (BOOL)chainQueueHasTracks
{
return [controller chainQueueHasTracks];
}
- (double)secondsBuffered
{
return (double)([buffer bufferedLength]) / (format.mSampleRate * format.mBytesPerPacket);
}
- (int)readData:(void *)ptr amount:(int)amount
{
@autoreleasepool {
int n;
[self setPreviousNode:[[controller bufferChain] finalNode]];
n = [super readData:ptr amount:amount];
/* if (n == 0) {
DLog(@"Output Buffer dry!");
}
*/
return n;
}
}
- (double)amountPlayed
{
return amountPlayed;
}
- (AudioStreamBasicDescription) format
{
return format;
}
- (void)setFormat:(AudioStreamBasicDescription *)f
{
format = *f;
// Calculate a ratio and add to double(seconds) instead, as format may change
// double oldSampleRatio = sampleRatio;
sampleRatio = 1.0 / (format.mSampleRate * format.mBytesPerPacket);
BufferChain *bufferChain = [controller bufferChain];
if (bufferChain)
{
ConverterNode *converter = [bufferChain converter];
if (converter)
{
// This clears the resampler buffer, but not the input buffer
// We also have to jump the play position ahead accounting for
// the data we are flushing
#if 0
// We no longer need to do this, because outputchanged converter
// now uses the RefillNode to slap the previous samples into
// itself
if (oldSampleRatio)
amountPlayed += oldSampleRatio * [[converter buffer] bufferedLength];
#endif
AudioStreamBasicDescription inf = [bufferChain inputFormat];
format.mChannelsPerFrame = inf.mChannelsPerFrame;
format.mBytesPerFrame = ((format.mBitsPerChannel + 7) / 8) * format.mChannelsPerFrame;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
sampleRatio = 1.0 / (format.mSampleRate * format.mBytesPerPacket);
[converter setOutputFormat:format];
[converter inputFormatDidChange:[bufferChain inputFormat]];
}
}
}
- (void)close
{
[output stop];
output = nil;
}
- (void)setVolume:(double) v
{
[output setVolume:v];
}
- (void)setShouldContinue:(BOOL)s
{
[super setShouldContinue:s];
// if (s == NO)
// [output stop];
}
- (BOOL)isPaused
{
return paused;
}
- (void)beginEqualizer:(AudioUnit)eq
{
[controller beginEqualizer:eq];
}
- (void)refreshEqualizer:(AudioUnit)eq
{
[controller refreshEqualizer:eq];
}
- (void)endEqualizer:(AudioUnit)eq
{
[controller endEqualizer:eq];
}
- (void)sustainHDCD
{
[output sustainHDCD];
}
- (BOOL)formatChanged
{
[self setPreviousNode:[[controller bufferChain] finalNode]];
AudioStreamBasicDescription inf = [[self previousNode] nodeFormat];
if (!formatSetup || memcmp(&nodeFormat, &inf, sizeof(nodeFormat)) != 0) {
nodeFormat = inf;
formatSetup = YES;
formatChanged = YES;
}
BOOL copyFormatChanged = formatChanged;
formatChanged = NO;
return copyFormatChanged;
}
@end