Moved converter to a seperate node again.
parent
0584150ffd
commit
5ad2728d3c
|
@ -9,11 +9,12 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "InputNode.h"
|
||||
|
||||
#import "ConverterNode.h"
|
||||
#import "AudioPlayer.h"
|
||||
|
||||
@interface BufferChain : NSObject {
|
||||
InputNode *inputNode;
|
||||
ConverterNode *converterNode;
|
||||
|
||||
NSURL *streamURL;
|
||||
id userInfo;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
userInfo = nil;
|
||||
|
||||
inputNode = nil;
|
||||
converterNode = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -31,10 +32,12 @@
|
|||
- (void)buildChain
|
||||
{
|
||||
[inputNode release];
|
||||
[converterNode release];
|
||||
|
||||
inputNode = [[InputNode alloc] initWithController:self previous:nil];
|
||||
|
||||
finalNode = inputNode;
|
||||
converterNode = [[ConverterNode alloc] initWithController:self previous:inputNode];
|
||||
|
||||
finalNode = converterNode;
|
||||
}
|
||||
|
||||
- (BOOL)open:(NSURL *)url withOutputFormat:(AudioStreamBasicDescription)outputFormat
|
||||
|
@ -54,6 +57,9 @@
|
|||
|
||||
if (![inputNode openURL:url withSource:source outputFormat:outputFormat])
|
||||
return NO;
|
||||
|
||||
if (![converterNode setupWithInputFormat:propertiesToASBD([inputNode properties]) outputFormat:outputFormat])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
@ -61,6 +67,7 @@
|
|||
- (void)launchThreads
|
||||
{
|
||||
[inputNode launchThread];
|
||||
[converterNode launchThread];
|
||||
}
|
||||
|
||||
- (void)setUserInfo:(id)i
|
||||
|
@ -80,6 +87,7 @@
|
|||
[userInfo release];
|
||||
|
||||
[inputNode release];
|
||||
[converterNode release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -120,6 +128,7 @@
|
|||
- (void)setShouldContinue:(BOOL)s
|
||||
{
|
||||
[inputNode setShouldContinue:s];
|
||||
[converterNode setShouldContinue:s];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// ConverterNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/2/05.
|
||||
// Copyright 2005 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import <CoreAudio/AudioHardware.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
@interface Converter : NSObject
|
||||
{
|
||||
AudioConverterRef converter;
|
||||
|
||||
void *outputBuffer;
|
||||
int outputBufferSize;
|
||||
|
||||
//Temporary for callback use
|
||||
void *inputBuffer;
|
||||
int inputBufferSize;
|
||||
BOOL needsReset;
|
||||
//end
|
||||
|
||||
int outputSize;
|
||||
|
||||
AudioStreamBasicDescription inputFormat;
|
||||
AudioStreamBasicDescription outputFormat;
|
||||
}
|
||||
|
||||
- (void *)outputBuffer;
|
||||
- (int)outputBufferSize;
|
||||
|
||||
- (void)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat outputFormat:(AudioStreamBasicDescription)outputFormat;
|
||||
- (void)cleanUp;
|
||||
|
||||
- (void)reset;
|
||||
|
||||
//Returns the amount actually read from input
|
||||
- (int)convert:(void *)input amount:(int)inputSize;
|
||||
|
||||
@end
|
|
@ -1,167 +0,0 @@
|
|||
//
|
||||
// ConverterNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/2/05.
|
||||
// Copyright 2005 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Converter.h"
|
||||
#import "Node.h"
|
||||
|
||||
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||
{
|
||||
if (!inDesc) {
|
||||
printf ("Can't print a NULL desc!\n");
|
||||
return;
|
||||
}
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
|
||||
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
|
||||
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
|
||||
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
||||
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
||||
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
||||
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
||||
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
}
|
||||
|
||||
@implementation Converter
|
||||
|
||||
//called from the complexfill when the audio is converted...good clean fun
|
||||
static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData)
|
||||
{
|
||||
Converter *converter = (Converter *)inUserData;
|
||||
OSStatus err = noErr;
|
||||
|
||||
if (converter->inputBufferSize > 0) {
|
||||
int amountConverted = *ioNumberDataPackets * converter->inputFormat.mBytesPerPacket;
|
||||
if (amountConverted > converter->inputBufferSize) {
|
||||
amountConverted = converter->inputBufferSize;
|
||||
}
|
||||
|
||||
ioData->mBuffers[0].mData = converter->inputBuffer;
|
||||
ioData->mBuffers[0].mDataByteSize = amountConverted;
|
||||
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
|
||||
ioData->mNumberBuffers = 1;
|
||||
|
||||
*ioNumberDataPackets = amountConverted / converter->inputFormat.mBytesPerPacket;
|
||||
|
||||
converter->inputBufferSize -= amountConverted;
|
||||
converter->inputBuffer = ((char *)converter->inputBuffer) + amountConverted;
|
||||
}
|
||||
else {
|
||||
ioData->mBuffers[0].mData = NULL;
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
ioData->mNumberBuffers = 1;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
//Reset the converter's internal bufferrs.
|
||||
converter->needsReset = YES;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
AudioConverterReset(converter);
|
||||
}
|
||||
|
||||
- (int)convert:(void *)input amount:(int)inputSize
|
||||
{
|
||||
AudioBufferList ioData;
|
||||
UInt32 ioNumberFrames;
|
||||
|
||||
if (inputSize <= 0) {
|
||||
outputBufferSize = inputSize;
|
||||
return inputSize;
|
||||
}
|
||||
|
||||
OSStatus err;
|
||||
|
||||
needsReset = NO;
|
||||
|
||||
ioNumberFrames = inputSize/inputFormat.mBytesPerFrame;
|
||||
ioData.mBuffers[0].mData = outputBuffer;
|
||||
ioData.mBuffers[0].mDataByteSize = outputSize;
|
||||
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
|
||||
ioData.mNumberBuffers = 1;
|
||||
inputBuffer = input;
|
||||
inputBufferSize = inputSize;
|
||||
|
||||
err = AudioConverterFillComplexBuffer(converter, ACInputProc, self, &ioNumberFrames, &ioData, NULL);
|
||||
if (err != noErr || needsReset) //It returns insz at EOS at times...so run it again to make sure all data is converted
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
outputBufferSize = ioData.mBuffers[0].mDataByteSize;
|
||||
|
||||
return inputSize - inputBufferSize;
|
||||
}
|
||||
|
||||
- (void)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
|
||||
{
|
||||
//Make the converter
|
||||
OSStatus stat = noErr;
|
||||
|
||||
inputFormat = inf;
|
||||
outputFormat = outf;
|
||||
|
||||
stat = AudioConverterNew ( &inputFormat, &outputFormat, &converter);
|
||||
if (stat != noErr)
|
||||
{
|
||||
NSLog(@"Error creating converter %i", stat);
|
||||
}
|
||||
|
||||
if (inputFormat.mChannelsPerFrame == 1)
|
||||
{
|
||||
SInt32 channelMap[2] = { 0, 0 };
|
||||
|
||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,sizeof(channelMap),channelMap);
|
||||
if (stat != noErr)
|
||||
{
|
||||
NSLog(@"Error mapping channels %i", stat);
|
||||
}
|
||||
}
|
||||
|
||||
outputSize = CHUNK_SIZE;
|
||||
UInt32 dataSize = sizeof(outputSize);
|
||||
AudioConverterGetProperty(converter,
|
||||
kAudioConverterPropertyCalculateOutputBufferSize,
|
||||
&dataSize,
|
||||
(void*)&outputSize);
|
||||
|
||||
if (outputBuffer)
|
||||
{
|
||||
free(outputBuffer);
|
||||
}
|
||||
outputBuffer = malloc(outputSize);
|
||||
|
||||
//PrintStreamDesc(&inf);
|
||||
//PrintStreamDesc(&outf);
|
||||
}
|
||||
|
||||
|
||||
- (void *)outputBuffer
|
||||
{
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
- (int)outputBufferSize
|
||||
{
|
||||
return outputBufferSize;
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
if (outputBuffer) {
|
||||
free(outputBuffer);
|
||||
outputBuffer = NULL;
|
||||
}
|
||||
AudioConverterDispose(converter);
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ConverterNode.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import <CoreAudio/AudioHardware.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
|
||||
#import "Node.h"
|
||||
|
||||
@interface ConverterNode : Node {
|
||||
AudioConverterRef converter;
|
||||
void *callbackBuffer;
|
||||
|
||||
AudioStreamBasicDescription inputFormat;
|
||||
AudioStreamBasicDescription outputFormat;
|
||||
}
|
||||
|
||||
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inputFormat outputFormat:(AudioStreamBasicDescription)outputFormat;
|
||||
- (void)cleanUp;
|
||||
|
||||
- (void)process;
|
||||
- (int)convert:(void *)dest amount:(int)amount;
|
||||
|
||||
@end
|
|
@ -0,0 +1,431 @@
|
|||
//
|
||||
// ConverterNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 8/2/05.
|
||||
// Copyright 2005 Vincent Spader. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Converter.h"
|
||||
#import "Node.h"
|
||||
|
||||
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||
{
|
||||
if (!inDesc) {
|
||||
printf ("Can't print a NULL desc!\n");
|
||||
return;
|
||||
}
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
|
||||
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
|
||||
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
|
||||
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
||||
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
||||
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
||||
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
||||
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
}
|
||||
|
||||
@implementation Converter
|
||||
|
||||
//called from the complexfill when the audio is converted...good clean fun
|
||||
static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData)
|
||||
{
|
||||
Converter *converter = (Converter *)inUserData;
|
||||
OSStatus err = noErr;
|
||||
|
||||
if (converter->inputBufferSize > 0) {
|
||||
int amountConverted = *ioNumberDataPackets * converter->inputFormat.mBytesPerPacket;
|
||||
if (amountConverted > converter->inputBufferSize) {
|
||||
amountConverted = converter->inputBufferSize;
|
||||
}
|
||||
|
||||
ioData->mBuffers[0].mData = converter->inputBuffer;
|
||||
ioData->mBuffers[0].mDataByteSize = amountConverted;
|
||||
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
|
||||
ioData->mNumberBuffers = 1;
|
||||
|
||||
*ioNumberDataPackets = amountConverted / converter->inputFormat.mBytesPerPacket;
|
||||
|
||||
converter->inputBufferSize -= amountConverted;
|
||||
converter->inputBuffer = ((char *)converter->inputBuffer) + amountConverted;
|
||||
}
|
||||
else {
|
||||
ioData->mBuffers[0].mData = NULL;
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
ioData->mNumberBuffers = 1;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
//Reset the converter's internal bufferrs.
|
||||
converter->needsReset = YES;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
AudioConverterReset(converter);
|
||||
}
|
||||
|
||||
- (int)convert:(void *)input amount:(int)inputSize
|
||||
{
|
||||
AudioBufferList ioData;
|
||||
UInt32 ioNumberFrames;
|
||||
|
||||
if (inputSize <= 0) {
|
||||
outputBufferSize = inputSize;
|
||||
return inputSize;
|
||||
}
|
||||
|
||||
OSStatus err;
|
||||
|
||||
needsReset = NO;
|
||||
|
||||
ioNumberFrames = inputSize/inputFormat.mBytesPerFrame;
|
||||
ioData.mBuffers[0].mData = outputBuffer;
|
||||
ioData.mBuffers[0].mDataByteSize = outputSize;
|
||||
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
|
||||
ioData.mNumberBuffers = 1;
|
||||
inputBuffer = input;
|
||||
inputBufferSize = inputSize;
|
||||
|
||||
err = AudioConverterFillComplexBuffer(converter, ACInputProc, self, &ioNumberFrames, &ioData, NULL);
|
||||
if (err != noErr || needsReset) //It returns insz at EOS at times...so run it again to make sure all data is converted
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
outputBufferSize = ioData.mBuffers[0].mDataByteSize;
|
||||
|
||||
return inputSize - inputBufferSize;
|
||||
}
|
||||
|
||||
- (void)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
|
||||
{
|
||||
//Make the converter
|
||||
OSStatus stat = noErr;
|
||||
|
||||
inputFormat = inf;
|
||||
outputFormat = outf;
|
||||
|
||||
stat = AudioConverterNew ( &inputFormat, &outputFormat, &converter);
|
||||
if (stat != noErr)
|
||||
{
|
||||
NSLog(@"Error creating converter %i", stat);
|
||||
}
|
||||
|
||||
if (inputFormat.mChannelsPerFrame == 1)
|
||||
{
|
||||
SInt32 channelMap[2] = { 0, 0 };
|
||||
|
||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,sizeof(channelMap),channelMap);
|
||||
if (stat != noErr)
|
||||
{
|
||||
NSLog(@"Error mapping channels %i", stat);
|
||||
}
|
||||
}
|
||||
|
||||
outputSize = CHUNK_SIZE;
|
||||
UInt32 dataSize = sizeof(outputSize);
|
||||
AudioConverterGetProperty(converter,
|
||||
kAudioConverterPropertyCalculateOutputBufferSize,
|
||||
&dataSize,
|
||||
(void*)&outputSize);
|
||||
|
||||
if (outputBuffer)
|
||||
{
|
||||
free(outputBuffer);
|
||||
}
|
||||
outputBuffer = malloc(outputSize);//
|
||||
// ConverterNode.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ConverterNode.h"
|
||||
|
||||
#define BUFFER_SIZE 512 * 1024
|
||||
#define CHUNK_SIZE 16 * 1024
|
||||
|
||||
|
||||
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||
{
|
||||
if (!inDesc) {
|
||||
printf ("Can't print a NULL desc!\n");
|
||||
return;
|
||||
}
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
|
||||
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
|
||||
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
|
||||
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
||||
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
||||
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
||||
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
||||
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
}
|
||||
|
||||
@implementation ConverterNode
|
||||
|
||||
//called from the complexfill when the audio is converted...good clean fun
|
||||
static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData)
|
||||
{
|
||||
ConverterNode *converter = (ConverterNode *)inUserData;
|
||||
id previousNode = [converter previousNode];
|
||||
OSStatus err = noErr;
|
||||
void *readPtr;
|
||||
int amountToWrite;
|
||||
int availInput;
|
||||
int amountRead;
|
||||
|
||||
if ([converter shouldContinue] == NO || [converter endOfStream] == YES)
|
||||
{
|
||||
// NSLog(@"END OF STREAM IN CONV");
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
amountToWrite = (*ioNumberDataPackets)*(converter->inputFormat.mBytesPerPacket);
|
||||
|
||||
if (converter->callbackBuffer != NULL)
|
||||
free(converter->callbackBuffer);
|
||||
converter->callbackBuffer = malloc(amountToWrite);
|
||||
|
||||
amountRead = [converter readData:converter->callbackBuffer amount:amountToWrite];
|
||||
/* if ([converter endOfStream] == YES)
|
||||
{
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
*/ if (amountRead == 0)
|
||||
{
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
return 100; //Keep asking for data
|
||||
}
|
||||
|
||||
/*
|
||||
availInput = [[previousNode buffer] lengthAvailableToReadReturningPointer:&readPtr];
|
||||
if (availInput == 0 )
|
||||
{
|
||||
// NSLog(@"0 INPUT");
|
||||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
if ([previousNode endOfStream] == YES)
|
||||
{
|
||||
NSLog(@"END OF CONVERTER INPUT");
|
||||
[converter setEndOfStream:YES];
|
||||
[converter setShouldContinue:NO];
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
return 100; //Keep asking for data
|
||||
}
|
||||
|
||||
if (amountToWrite > availInput)
|
||||
amountToWrite = availInput;
|
||||
|
||||
*ioNumberDataPackets = amountToWrite/(converter->inputFormat.mBytesPerPacket);
|
||||
|
||||
if (converter->callbackBuffer != NULL)
|
||||
free(converter->callbackBuffer);
|
||||
converter->callbackBuffer = malloc(amountToWrite);
|
||||
memcpy(converter->callbackBuffer, readPtr, amountToWrite);
|
||||
|
||||
if (amountToWrite > 0)
|
||||
{
|
||||
[[previousNode buffer] didReadLength:amountToWrite];
|
||||
[[previousNode semaphore] signal];
|
||||
}
|
||||
*/
|
||||
// NSLog(@"Amount read: %@ %i", converter, amountRead);
|
||||
ioData->mBuffers[0].mData = converter->callbackBuffer;
|
||||
ioData->mBuffers[0].mDataByteSize = amountRead;
|
||||
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
|
||||
ioData->mNumberBuffers = 1;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
-(void)process
|
||||
{
|
||||
char writeBuf[CHUNK_SIZE];
|
||||
int amountConverted;
|
||||
|
||||
|
||||
while ([self shouldContinue] == YES) //Need to watch EOS somehow....
|
||||
{
|
||||
amountConverted = [self convert:writeBuf amount:CHUNK_SIZE];
|
||||
|
||||
// NSLog(@"Amount converted %@: %i %i", self, amountConverted, [self endOfStream]);
|
||||
if (amountConverted == 0 && [self endOfStream] == YES)
|
||||
{
|
||||
// NSLog(@"END OF STREAM FOR ZINE DINNER!!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
[self writeData:writeBuf amount:amountConverted];
|
||||
}
|
||||
|
||||
/* void *writePtr;
|
||||
int availOutput;
|
||||
int amountConverted;
|
||||
|
||||
while ([self shouldContinue] == YES)
|
||||
{
|
||||
|
||||
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
|
||||
|
||||
while (availOutput == 0)
|
||||
{
|
||||
[semaphore wait];
|
||||
|
||||
if (shouldContinue == NO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
|
||||
}
|
||||
|
||||
amountConverted = [self convert:writePtr amount:availOutput];
|
||||
|
||||
if (amountConverted > 0)
|
||||
[buffer didWriteLength:amountConverted];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
- (int)convert:(void *)dest amount:(int)amount
|
||||
{
|
||||
AudioBufferList ioData;
|
||||
UInt32 ioNumberFrames;
|
||||
OSStatus err;
|
||||
|
||||
ioNumberFrames = amount/outputFormat.mBytesPerFrame;
|
||||
ioData.mBuffers[0].mData = dest;
|
||||
ioData.mBuffers[0].mDataByteSize = amount;
|
||||
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
|
||||
ioData.mNumberBuffers = 1;
|
||||
|
||||
err = AudioConverterFillComplexBuffer(converter, ACInputProc, self, &ioNumberFrames, &ioData, NULL);
|
||||
if (err == kAudioConverterErr_InvalidInputSize) //It returns insz at EOS at times...so run it again to make sure all data is converted
|
||||
{
|
||||
return [self convert:dest amount:amount];
|
||||
}
|
||||
// if (err != noErr)
|
||||
// NSLog(@"Converter error: %i", err);
|
||||
|
||||
return ioData.mBuffers[0].mDataByteSize;
|
||||
/*
|
||||
void *readPtr;
|
||||
int availInput;
|
||||
|
||||
availInput = [[previousLink buffer] lengthAvailableToReadReturningPointer:&readPtr];
|
||||
// NSLog(@"AMOUNT: %i %i", amount, availInput);
|
||||
|
||||
if (availInput == 0)
|
||||
{
|
||||
if ([previousLink endOfInput] == YES)
|
||||
{
|
||||
endOfInput = YES;
|
||||
NSLog(@"EOI");
|
||||
shouldContinue = NO;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (availInput < amount)
|
||||
amount = availInput;
|
||||
|
||||
memcpy(dest, readPtr, amount);
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
// NSLog(@"READ: %i", amount);
|
||||
[[previousLink buffer] didReadLength:amount];
|
||||
[[previousLink semaphore] signal];
|
||||
}
|
||||
|
||||
return amount;
|
||||
*/
|
||||
}
|
||||
|
||||
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
|
||||
{
|
||||
//Make the converter
|
||||
OSStatus stat = noErr;
|
||||
|
||||
inputFormat = inf;
|
||||
outputFormat = outf;
|
||||
|
||||
stat = AudioConverterNew ( &inputFormat, &outputFormat, &converter);
|
||||
if (stat != noErr)
|
||||
{
|
||||
DBLog(@"Error creating converter %i", stat);
|
||||
}
|
||||
|
||||
if (inputFormat.mChannelsPerFrame == 1)
|
||||
{
|
||||
SInt32 channelMap[2] = { 0, 0 };
|
||||
|
||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,sizeof(channelMap),channelMap);
|
||||
if (stat != noErr)
|
||||
{
|
||||
DBLog(@"Error mapping channels %i", stat);
|
||||
}
|
||||
}
|
||||
|
||||
// DBLog(@"Created converter");
|
||||
PrintStreamDesc(&inf);
|
||||
PrintStreamDesc(&outf);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
AudioConverterDispose(converter);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//PrintStreamDesc(&inf);
|
||||
//PrintStreamDesc(&outf);
|
||||
}
|
||||
|
||||
|
||||
- (void *)outputBuffer
|
||||
{
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
- (int)outputBufferSize
|
||||
{
|
||||
return outputBufferSize;
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
if (outputBuffer) {
|
||||
free(outputBuffer);
|
||||
outputBuffer = NULL;
|
||||
}
|
||||
AudioConverterDispose(converter);
|
||||
}
|
||||
|
||||
@end
|
|
@ -13,13 +13,11 @@
|
|||
#import <AudioUnit/AudioUnit.h>
|
||||
|
||||
#import "AudioDecoder.h"
|
||||
#import "Converter.h"
|
||||
#import "Node.h"
|
||||
#import "Plugin.h"
|
||||
|
||||
@interface InputNode : Node {
|
||||
id<CogDecoder> decoder;
|
||||
Converter *converter;
|
||||
|
||||
AudioStreamBasicDescription outputFormat;
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
decoder = [AudioDecoder audioDecoderForURL:url];
|
||||
[decoder retain];
|
||||
|
||||
converter = [[Converter alloc] init];
|
||||
if (converter == nil)
|
||||
return NO;
|
||||
|
||||
[self registerObservers];
|
||||
|
||||
if (decoder == nil)
|
||||
|
@ -61,8 +57,6 @@
|
|||
{
|
||||
if ([keyPath isEqual:@"properties"]) {
|
||||
//Setup converter!
|
||||
[converter cleanUp];
|
||||
[converter setupWithInputFormat:propertiesToASBD([decoder properties]) outputFormat:outputFormat];
|
||||
//Inform something of properties change
|
||||
}
|
||||
else if ([keyPath isEqual:@"metadata"]) {
|
||||
|
@ -72,47 +66,46 @@
|
|||
|
||||
- (void)process
|
||||
{
|
||||
int amountRead = 0, amountConverted = 0, amountInBuffer = 0;
|
||||
int amountRead = 0, amountInBuffer = 0;
|
||||
void *inputBuffer = malloc(CHUNK_SIZE);
|
||||
|
||||
while ([self shouldContinue] == YES && [self endOfStream] == NO)
|
||||
{
|
||||
if (shouldSeek == YES)
|
||||
{
|
||||
NSLog(@"SEEKING!");
|
||||
[decoder seekToTime:seekTime];
|
||||
NSLog(@"Har");
|
||||
shouldSeek = NO;
|
||||
|
||||
NSLog(@"Seeked! Resetting Buffer");
|
||||
|
||||
[self resetBuffer];
|
||||
|
||||
NSLog(@"Reset buffer!");
|
||||
initialBufferFilled = NO;
|
||||
}
|
||||
|
||||
if (amountInBuffer < CHUNK_SIZE) {
|
||||
amountRead = [decoder fillBuffer:((char *)inputBuffer) + amountInBuffer ofSize:CHUNK_SIZE - amountInBuffer];
|
||||
amountInBuffer += amountRead;
|
||||
}
|
||||
|
||||
amountConverted = [converter convert:inputBuffer amount:amountInBuffer]; //Convert fills in converter buffer, til the next call
|
||||
if (amountInBuffer - amountConverted > 0) {
|
||||
memmove(inputBuffer,((char *)inputBuffer) + amountConverted, amountInBuffer - amountConverted);
|
||||
}
|
||||
amountInBuffer -= amountConverted;
|
||||
|
||||
if ([converter outputBufferSize] <= 0)
|
||||
{
|
||||
if (initialBufferFilled == NO) {
|
||||
[controller initialBufferFilled];
|
||||
if (amountRead <= 0)
|
||||
{
|
||||
if (initialBufferFilled == NO) {
|
||||
[controller initialBufferFilled];
|
||||
}
|
||||
|
||||
endOfStream = YES;
|
||||
[controller endOfInputReached];
|
||||
break; //eof
|
||||
}
|
||||
|
||||
endOfStream = YES;
|
||||
[controller endOfInputReached];
|
||||
break; //eof
|
||||
|
||||
[self writeData:inputBuffer amount:amountInBuffer];
|
||||
amountInBuffer = 0;
|
||||
}
|
||||
|
||||
[self writeData:[converter outputBuffer] amount:[converter outputBufferSize]];
|
||||
}
|
||||
|
||||
[decoder close];
|
||||
[converter cleanUp];
|
||||
|
||||
free(inputBuffer);
|
||||
}
|
||||
|
@ -121,7 +114,7 @@
|
|||
{
|
||||
seekTime = time;
|
||||
shouldSeek = YES;
|
||||
[self resetBuffer];
|
||||
NSLog(@"Should seek!");
|
||||
[semaphore signal];
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
id previousNode;
|
||||
id controller;
|
||||
|
||||
BOOL shouldReset;
|
||||
|
||||
BOOL shouldContinue;
|
||||
BOOL endOfStream; //All data is now in buffer
|
||||
BOOL initialBufferFilled;
|
||||
|
@ -36,6 +38,9 @@
|
|||
|
||||
- (void)launchThread;
|
||||
|
||||
- (void)setShouldReset:(BOOL)s;
|
||||
- (BOOL)shouldReset;
|
||||
|
||||
- (NSLock *)readLock;
|
||||
- (NSLock *)writeLock;
|
||||
|
||||
|
@ -49,6 +54,8 @@
|
|||
|
||||
- (Semaphore *)semaphore;
|
||||
|
||||
-(void)resetBuffer;
|
||||
|
||||
- (BOOL)endOfStream;
|
||||
- (void)setEndOfStream:(BOOL)e;
|
||||
|
||||
|
|
|
@ -41,15 +41,17 @@
|
|||
while (shouldContinue == YES && amountLeft > 0)
|
||||
{
|
||||
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
|
||||
|
||||
if (availOutput == 0)
|
||||
{
|
||||
[writeLock unlock];
|
||||
if (availOutput == 0) {
|
||||
if (initialBufferFilled == NO) {
|
||||
initialBufferFilled = YES;\
|
||||
initialBufferFilled = YES;
|
||||
if ([controller respondsToSelector:@selector(initialBufferFilled)])
|
||||
[controller performSelector:@selector(initialBufferFilled)];
|
||||
}
|
||||
}
|
||||
|
||||
if (availOutput == 0 || shouldReset)
|
||||
{
|
||||
[writeLock unlock];
|
||||
[semaphore wait];
|
||||
[writeLock lock];
|
||||
}
|
||||
|
@ -115,6 +117,19 @@
|
|||
NSLog(@"BUFFER IN DANGER");
|
||||
}
|
||||
*/
|
||||
|
||||
if ([previousNode shouldReset] == YES) {
|
||||
[writeLock lock];
|
||||
|
||||
[buffer empty];
|
||||
|
||||
shouldReset = YES;
|
||||
[previousNode setShouldReset: NO];
|
||||
[writeLock unlock];
|
||||
|
||||
[[previousNode semaphore] signal];
|
||||
}
|
||||
|
||||
amountToCopy = availInput;
|
||||
if (amountToCopy > amount)
|
||||
{
|
||||
|
@ -161,13 +176,12 @@
|
|||
|
||||
- (void)resetBuffer
|
||||
{
|
||||
[readLock lock];
|
||||
[writeLock lock];
|
||||
|
||||
[buffer empty];
|
||||
|
||||
[writeLock unlock];
|
||||
[readLock unlock];
|
||||
shouldReset = YES; //Will reset on next write.
|
||||
if (previousNode == nil) {
|
||||
[readLock lock];
|
||||
[buffer empty];
|
||||
[readLock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSLock *)readLock
|
||||
|
@ -195,4 +209,14 @@
|
|||
endOfStream = e;
|
||||
}
|
||||
|
||||
- (void)setShouldReset:(BOOL)s
|
||||
{
|
||||
shouldReset = s;
|
||||
}
|
||||
- (BOOL)shouldReset
|
||||
{
|
||||
return shouldReset;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
- (void)seek:(double)time
|
||||
{
|
||||
[output pause];
|
||||
// [output pause];
|
||||
|
||||
amountPlayed = time*format.mBytesPerFrame*(format.mSampleRate/1000.0);
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F94DD40B8D0F7000A34E87 /* PluginController.m */; };
|
||||
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DDC0B8D101100A34E87 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
|
||||
8EC1225F0B993BD500C5B3AD /* Converter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC1225D0B993BD500C5B3AD /* Converter.h */; };
|
||||
8EC122600B993BD500C5B3AD /* Converter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1225E0B993BD500C5B3AD /* Converter.m */; };
|
||||
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC1225D0B993BD500C5B3AD /* ConverterNode.h */; };
|
||||
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1225E0B993BD500C5B3AD /* ConverterNode.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -103,8 +103,8 @@
|
|||
32DBCF5E0370ADEE00C91783 /* CogAudio_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogAudio_Prefix.pch; sourceTree = "<group>"; };
|
||||
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
8DC2EF5B0486A6940098B216 /* CogAudio.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CogAudio.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8EC1225D0B993BD500C5B3AD /* Converter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Converter.h; sourceTree = "<group>"; };
|
||||
8EC1225E0B993BD500C5B3AD /* Converter.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Converter.m; sourceTree = "<group>"; };
|
||||
8EC1225D0B993BD500C5B3AD /* ConverterNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ConverterNode.h; sourceTree = "<group>"; };
|
||||
8EC1225E0B993BD500C5B3AD /* ConverterNode.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ConverterNode.m; sourceTree = "<group>"; };
|
||||
D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -213,8 +213,8 @@
|
|||
children = (
|
||||
17D21C760B8BE4BA00D1EBDE /* BufferChain.h */,
|
||||
17D21C770B8BE4BA00D1EBDE /* BufferChain.m */,
|
||||
8EC1225D0B993BD500C5B3AD /* Converter.h */,
|
||||
8EC1225E0B993BD500C5B3AD /* Converter.m */,
|
||||
8EC1225D0B993BD500C5B3AD /* ConverterNode.h */,
|
||||
8EC1225E0B993BD500C5B3AD /* ConverterNode.m */,
|
||||
17D21C7A0B8BE4BA00D1EBDE /* InputNode.h */,
|
||||
17D21C7B0B8BE4BA00D1EBDE /* InputNode.m */,
|
||||
17D21C7C0B8BE4BA00D1EBDE /* Node.h */,
|
||||
|
@ -304,7 +304,7 @@
|
|||
17C940230B900909008627D6 /* AudioMetadataReader.h in Headers */,
|
||||
17B619300B909BC300BC003F /* AudioPropertiesReader.h in Headers */,
|
||||
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */,
|
||||
8EC1225F0B993BD500C5B3AD /* Converter.h in Headers */,
|
||||
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -377,7 +377,7 @@
|
|||
17C940240B900909008627D6 /* AudioMetadataReader.m in Sources */,
|
||||
17B619310B909BC300BC003F /* AudioPropertiesReader.m in Sources */,
|
||||
17ADB13D0B97926D00257CA2 /* AudioSource.m in Sources */,
|
||||
8EC122600B993BD500C5B3AD /* Converter.m in Sources */,
|
||||
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -1516,7 +1516,7 @@
|
|||
);
|
||||
PRODUCT_NAME = Cog;
|
||||
WRAPPER_EXTENSION = app;
|
||||
ZERO_LINK = YES;
|
||||
ZERO_LINK = NO;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue