cog/Audio/Chain/InputNode.m

357 lines
9.9 KiB
Objective-C

//
// InputNode.m
// Cog
//
// Created by Vincent Spader on 8/2/05.
// Copyright 2005 Vincent Spader. All rights reserved.
//
#import "InputNode.h"
#import "BufferChain.h"
#import "Plugin.h"
#import "CoreAudioUtils.h"
static BOOL hostIsBigEndian()
{
#ifdef __BIG_ENDIAN__
return YES;
#else
return NO;
#endif
}
@implementation InputNode
- (BOOL)openWithSource:(id<CogSource>)source
{
decoder = [AudioDecoder audioDecoderForSource:source];
[decoder retain];
if (decoder == nil)
return NO;
[self registerObservers];
if (![decoder open:source])
{
NSLog(@"Couldn't open decoder...");
return NO;
}
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerSample = bitsPerSample / 8;
bytesPerFrame = bytesPerSample * channels;
if (([[properties objectForKey:@"endian"] isEqualToString:@"big"] && !hostIsBigEndian()) ||
([[properties objectForKey:@"endian"] isEqualToString:@"little"] && hostIsBigEndian())) {
swapEndian = YES;
}
else {
swapEndian = NO;
}
[self refreshVolumeScaling];
shouldContinue = YES;
shouldSeek = NO;
return YES;
}
- (BOOL)openWithDecoder:(id<CogDecoder>) d
{
NSLog(@"Opening with old decoder: %@", d);
decoder = d;
[decoder retain];
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerSample = bitsPerSample / 8;
bytesPerFrame = bytesPerSample * channels;
[self refreshVolumeScaling];
[self registerObservers];
shouldContinue = YES;
shouldSeek = NO;
NSLog(@"DONES: %@", decoder);
return YES;
}
- (void)registerObservers
{
NSLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:NULL];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:NULL];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"SOMETHING CHANGED!");
if ([keyPath isEqual:@"properties"]) {
//Setup converter!
//Inform something of properties change
//Disable support until it is properly implimented.
//[controller inputFormatDidChange: propertiesToASBD([decoder properties])];
[self refreshVolumeScaling];
}
else if ([keyPath isEqual:@"metadata"]) {
//Inform something of metadata change
}
else if ([keyPath isEqual:@"values.volumeScaling"]) {
//User reset the volume scaling option
[self refreshVolumeScaling];
}
}
static float db_to_scale(float db)
{
return pow(10.0, db / 20);
}
- (void)refreshVolumeScaling
{
NSDictionary *properties = [decoder properties];
if (rgInfo != nil)
properties = rgInfo;
NSString * scaling = [[NSUserDefaults standardUserDefaults] stringForKey:@"volumeScaling"];
BOOL useAlbum = [scaling hasPrefix:@"albumGain"];
BOOL useTrack = useAlbum || [scaling hasPrefix:@"trackGain"];
BOOL useVolume = useAlbum || useTrack || [scaling isEqualToString:@"volumeScale"];
BOOL usePeak = [scaling hasSuffix:@"WithPeak"];
float scale = 1.0;
float peak = 0.0;
if (useVolume) {
id pVolumeScale = [properties objectForKey:@"volume"];
if (pVolumeScale != nil)
scale = [pVolumeScale floatValue];
}
if (useTrack) {
id trackGain = [properties objectForKey:@"replayGainTrackGain"];
id trackPeak = [properties objectForKey:@"replayGainTrackPeak"];
if (trackGain != nil)
scale = db_to_scale([trackGain floatValue]);
if (trackPeak != nil)
peak = [trackPeak floatValue];
}
if (useAlbum) {
id albumGain = [properties objectForKey:@"replayGainAlbumGain"];
id albumPeak = [properties objectForKey:@"replayGainAlbumPeak"];
if (albumGain != nil)
scale = db_to_scale([albumGain floatValue]);
if (albumPeak != nil)
peak = [albumPeak floatValue];
}
if (usePeak) {
if (scale * peak > 1.0)
scale = 1.0 / peak;
}
volumeScale = scale * 4096;
}
static int16_t swap_16(uint16_t input)
{
return (input >> 8) | (input << 8);
}
static int32_t swap_24(uint32_t input)
{
int32_t temp = (input << 24) >> 8;
return temp | ((input >> 16) & 0xff) | (input & 0xff00);
}
static int32_t swap_32(uint32_t input)
{
return (input >> 24) | ((input >> 8) & 0xff00) | ((input << 8) & 0xff0000) | (input << 24);
}
- (void)process
{
int amountInBuffer = 0;
void *inputBuffer = malloc(CHUNK_SIZE);
BOOL shouldClose = YES;
while ([self shouldContinue] == YES && [self endOfStream] == NO)
{
if (shouldSeek == YES)
{
NSLog(@"SEEKING!");
[decoder seek:seekFrame];
shouldSeek = NO;
NSLog(@"Seeked! Resetting Buffer");
[self resetBuffer];
NSLog(@"Reset buffer!");
initialBufferFilled = NO;
}
if (amountInBuffer < CHUNK_SIZE) {
int framesToRead = (CHUNK_SIZE - amountInBuffer)/bytesPerFrame;
int framesRead = [decoder readAudio:((char *)inputBuffer) + amountInBuffer frames:framesToRead];
amountInBuffer += (framesRead * bytesPerFrame);
if (framesRead <= 0)
{
if (initialBufferFilled == NO) {
[controller initialBufferFilled:self];
}
NSLog(@"End of stream? %@", [self properties]);
endOfStream = YES;
shouldClose = [controller endOfInputReached]; //Lets us know if we should keep going or not (occassionally, for track changes within a file)
NSLog(@"closing? is %i", shouldClose);
break;
}
if (volumeScale != 4096) {
int totalFrames = amountInBuffer / bytesPerSample;
switch (bytesPerSample) {
case 1:
{
uint8_t * samples = (uint8_t *)inputBuffer;
for (int i = 0; i < totalFrames; i++)
{
int32_t sample = (int8_t)samples[i] - 128;
sample = (sample * volumeScale) >> 12;
if ((unsigned)(sample + 0x80) & 0xffffff00) sample = (sample >> 31) ^ 0x7f;
samples[i] = sample + 128;
}
}
break;
case 2:
{
int16_t * samples = (int16_t *)inputBuffer;
for (int i = 0; i < totalFrames; i++)
{
int32_t sample = samples[i];
if (swapEndian) sample = swap_16(sample);
sample = (sample * volumeScale) >> 12;
if ((unsigned)(sample + 0x8000) & 0xffff0000) sample = (sample >> 31) ^ 0x7fff;
if (swapEndian) sample = swap_16(sample);
samples[i] = sample;
}
}
break;
case 3:
{
uint8_t * samples = (uint8_t *)inputBuffer;
for (int i = 0; i < totalFrames; i++)
{
int32_t sample = (samples[i * 3] << 8) | (samples[i * 3 + 1] << 16) | (samples[i * 3 + 2] << 24);
sample >>= 8;
if (swapEndian) sample = swap_24(sample);
sample = (sample * volumeScale) >> 12;
if ((unsigned)(sample + 0x800000) & 0xff000000) sample = (sample >> 31) ^ 0x7fffff;
if (swapEndian) sample = swap_24(sample);
samples[i * 3] = sample;
samples[i * 3 + 1] = sample >> 8;
samples[i * 3 + 2] = sample >> 16;
}
}
break;
case 4:
{
int32_t * samples = (int32_t *)inputBuffer;
for (int i = 0; i < totalFrames; i++)
{
int64_t sample = samples[i];
if (swapEndian) sample = swap_32(sample);
sample = (sample * volumeScale) >> 12;
if ((unsigned)(sample + 0x80000000) & 0xffffffff00000000) sample = (sample >> 63) ^ 0x7fffffff;
if (swapEndian) sample = swap_32(sample);
samples[i] = sample;
}
}
break;
}
}
[self writeData:inputBuffer amount:amountInBuffer];
amountInBuffer = 0;
}
}
if (shouldClose)
[decoder close];
free(inputBuffer);
}
- (void)seek:(long)frame
{
seekFrame = frame;
shouldSeek = YES;
NSLog(@"Should seek!");
[semaphore signal];
}
- (BOOL)setTrack:(NSURL *)track
{
if ([decoder respondsToSelector:@selector(setTrack:)] && [decoder setTrack:track]) {
NSLog(@"SET TRACK!");
return YES;
}
return NO;
}
- (void)setRGInfo:(NSDictionary *)i
{
[i retain];
[rgInfo release];
rgInfo = i;
[self refreshVolumeScaling];
}
- (void)dealloc
{
NSLog(@"Input Node dealloc");
[rgInfo release];
[decoder removeObserver:self forKeyPath:@"properties"];
[decoder removeObserver:self forKeyPath:@"metadata"];
[decoder release];
[super dealloc];
}
- (NSDictionary *) properties
{
return [decoder properties];
}
- (id<CogDecoder>) decoder
{
return decoder;
}
@end