263 lines
6.3 KiB
Objective-C
263 lines
6.3 KiB
Objective-C
//
|
|
// 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;
|
|
*/
|
|
}
|
|
|
|
- (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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
- (void)cleanUp
|
|
{
|
|
AudioConverterDispose(converter);
|
|
}
|
|
|
|
@end
|