Overhaul of converter, bug fixes, and added position notification

CQTexperiment
vspader 2006-04-02 15:44:08 +00:00
parent f035fd1cc2
commit abc4edcda1
16 changed files with 253 additions and 98 deletions

View File

@ -20,6 +20,8 @@
IBOutlet NSButton *playButton;
NSTimer *positionTimer;
BOOL waitingForPlay; //No sneaky changing on us
SoundController *soundController;
@ -52,9 +54,8 @@
//Methods since this is SoundController's delegate
- (void)delegateNotifyStatusUpdate:(NSNumber *)status;
- (void)delegateNotifyPositionUpdate:(double)pos;
- (void)delegateNotifyBitrateUpdate:(float)bitrate;
- (void)delegateNotifySongChanged:(double)length;
- (void)delegateNotifySongChanged;
- (void)delegateRequestNextSong:(int)queueSize;
@end

View File

@ -86,6 +86,13 @@
// DBLog(@"PlayEntry: %@ Sent!", [pe filename]);
if (playbackStatus != kCogStatusStopped)
[self stop:self];
NSLog(@"LENGTH: %lf", [pe length]);
[positionSlider setMaxValue:[pe length]];
[positionSlider setDoubleValue:0.0f];
[self updateTimeField:0.0f];
[soundController play:[pe filename]];
}
@ -180,23 +187,26 @@
- (void)delegateRequestNextSong:(int)queueSize
{
PlaylistEntry *pe;
pe = [playlistController entryAtOffset:(queueSize+1)];
if (pe == nil)
[soundController setNextSong:nil];
else
{
NSLog(@"NEXT SONG: %@", [pe filename]);
[soundController setNextSong:[pe filename]];
}
}
- (void)delegateNotifySongChanged:(double)length
- (void)delegateNotifySongChanged
{
[playlistController next];
PlaylistEntry *pe = [playlistController currentEntry];;
// [positionSlider setMaxValue:length];
// [positionSlider setDoubleValue:0];
[positionSlider setMaxValue:[pe length]];
[positionSlider setDoubleValue:0.0f];
// [self updateTimeField:0.0f];
[self updateTimeField:0.0f];
}
@ -205,8 +215,10 @@
// [bitrateField setIntValue:bitrate];
}
- (void)delegateNotifyPositionUpdate:(double)pos
- (void)updatePosition:(id)sender
{
double pos = [soundController amountPlayed];
if ([positionSlider tracking] == NO)
{
// DBLog(@"Received pos update: %f", pos);
@ -221,11 +233,27 @@
int status = [s intValue];
if (status == kCogStatusStopped || status == kCogStatusPaused)
{
NSLog(@"INVALIDATING");
if (positionTimer)
{
[positionTimer invalidate];
positionTimer = NULL;
}
if (status == kCogStatusStopped)
{
[positionSlider setDoubleValue:0.0f];
[self updateTimeField:0.0f];
}
//Show play image
[self changePlayButtonImage:@"play"];
}
else if (status == kCogStatusPlaying)
{
if (!positionTimer)
positionTimer = [NSTimer scheduledTimerWithTimeInterval:1.00 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES];
//Show pause
[self changePlayButtonImage:@"pause"];
}

View File

@ -121,6 +121,7 @@ NSString *MovedRowsType = @"MOVED_ROWS_TYPE";
- (NSIndexSet *)indexSetFromRows:(NSArray *)rows
{
NSLog(@"HELLO");
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
NSEnumerator *rowEnumerator = [rows objectEnumerator];
NSNumber *idx;

View File

@ -1,5 +1,5 @@
//
// InputChain.h
// BufferChain.h
// CogNew
//
// Created by Zaphod Beeblebrox on 1/4/06.

View File

@ -1,5 +1,5 @@
//
// InputChain.m
// BufferChain.m
// CogNew
//
// Created by Zaphod Beeblebrox on 1/4/06.
@ -24,6 +24,9 @@
- (void)buildChain
{
[inputNode release];
[converterNode release];
inputNode = [[InputNode alloc] initWithController:soundController previous:nil];
converterNode = [[ConverterNode alloc] initWithController:soundController previous:inputNode];
@ -48,6 +51,14 @@
[converterNode launchThread];
}
- (void)dealloc
{
[inputNode release];
[converterNode release];
[super dealloc];
}
- (id)finalNode
{

View File

@ -1,5 +1,5 @@
//
// Converter.h
// ConverterNode.h
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.

View File

@ -1,5 +1,5 @@
//
// Converter.m
// ConverterNode.m
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
@ -41,9 +41,11 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
void *readPtr;
int amountToWrite;
int availInput;
int amountRead;
if ([converter shouldContinue] == NO)
if ([converter shouldContinue] == NO || [converter endOfStream] == YES)
{
// NSLog(@"END OF STREAM IN CONV");
ioData->mBuffers[0].mDataByteSize = 0;
*ioNumberDataPackets = 0;
@ -51,7 +53,28 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
}
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 )
{
@ -59,10 +82,10 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
ioData->mBuffers[0].mDataByteSize = 0;
*ioNumberDataPackets = 0;
if ([previousNode endOfInput] == YES)
if ([previousNode endOfStream] == YES)
{
NSLog(@"END OF CONVERTER INPUT");
[converter setEndOfInput:YES];
[converter setEndOfStream:YES];
[converter setShouldContinue:NO];
return noErr;
@ -86,9 +109,10 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
[[previousNode buffer] didReadLength:amountToWrite];
[[previousNode semaphore] signal];
}
*/
// NSLog(@"Amount read: %@ %i", converter, amountRead);
ioData->mBuffers[0].mData = converter->callbackBuffer;
ioData->mBuffers[0].mDataByteSize = amountToWrite;
ioData->mBuffers[0].mDataByteSize = amountRead;
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
ioData->mNumberBuffers = 1;
@ -97,12 +121,31 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
-(void)process
{
void *writePtr;
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)
@ -122,6 +165,7 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
if (amountConverted > 0)
[buffer didWriteLength:amountConverted];
}
*/
}
- (int)convert:(void *)dest amount:(int)amount
@ -137,8 +181,12 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter, UInt32* ioNumber
ioData.mNumberBuffers = 1;
err = AudioConverterFillComplexBuffer(converter, ACInputProc, self, &ioNumberFrames, &ioData, NULL);
// if (err != noErr)
// DBLog(@"Converter error: %i", err);
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;
/*

View File

@ -1,5 +1,5 @@
//
// InputController.h
// InputNode.h
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.

View File

@ -1,5 +1,5 @@
//
// InputController.m
// InputNode.m
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
@ -17,7 +17,7 @@
[soundFile getFormat:&format];
endOfInput = NO;
shouldContinue = YES;
}
- (void)process
@ -28,21 +28,20 @@
DBLog(@"Playing file.\n");
while ([self shouldContinue] == YES)
while ([self shouldContinue] == YES && [self endOfStream] == NO)
{
amountRead = [soundFile fillBuffer:buf ofSize: chunk_size];
if (amountRead <= 0)
{
endOfInput = YES;
endOfStream = YES;
NSLog(@"END OF INPUT WAS REACHED");
[controller endOfInputReached];
shouldContinue = NO;
[soundFile close];
return; //eof
}
[self writeData:buf amount:amountRead];
}
[soundFile close];
}

View File

@ -1,5 +1,5 @@
//
// InputChainLink.h
// Node.h
// CogNew
//
// Created by Zaphod Beeblebrox on 1/4/06.
@ -21,7 +21,7 @@
id controller;
BOOL shouldContinue;
BOOL endOfInput; //All data is now in buffer
BOOL endOfStream; //All data is now in buffer
}
- (id)initWithPrevious:(id)p;
@ -42,7 +42,7 @@
- (Semaphore *)semaphore;
- (BOOL)endOfInput;
- (void)setEndOfInput:(BOOL)e;
- (BOOL)endOfStream;
- (void)setEndOfStream:(BOOL)e;
@end

View File

@ -1,5 +1,5 @@
//
// InputChainLink.m
// Node.m
// CogNew
//
// Created by Zaphod Beeblebrox on 1/4/06.
@ -20,7 +20,8 @@
controller = c;
previousNode = p;
endOfInput = NO;
endOfStream = NO;
shouldContinue = YES;
}
return self;
@ -31,33 +32,30 @@
void *writePtr;
int amountToCopy, availOutput;
int amountLeft = amount;
do
while (shouldContinue == YES && amountLeft > 0)
{
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
while (availOutput < CHUNK_SIZE)
if (availOutput == 0)
{
[semaphore wait];
}
else
{
amountToCopy = availOutput;
if (amountToCopy > amountLeft)
amountToCopy = amountLeft;
if (shouldContinue == NO)
memcpy(writePtr, &((char *)ptr)[amount - amountLeft], amountToCopy);
if (amountToCopy > 0)
{
return (amount - amountLeft);
[buffer didWriteLength:amountToCopy];
}
availOutput = [buffer lengthAvailableToWriteReturningPointer:&writePtr];
amountLeft -= amountToCopy;
}
amountToCopy = availOutput;
if (amountToCopy > amountLeft)
amountToCopy = amountLeft;
memcpy(writePtr, &((char *)ptr)[amount - amountLeft], amountToCopy);
if (amountToCopy > 0)
{
[buffer didWriteLength:amountToCopy];
}
amountLeft -= amountToCopy;
} while (amountLeft > 0);
}
return (amount - amountLeft);
}
@ -72,8 +70,12 @@
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
DBLog(@"In thread entry");
[self retain];
[self process];
[self release];
[pool release];
}
@ -85,8 +87,17 @@
availInput = [[previousNode buffer] lengthAvailableToReadReturningPointer:&readPtr];
if (availInput <= amount && [previousNode endOfStream] == YES)
{
// NSLog(@"RELEASING: %i %i %i", availInput, [previousNode endOfStream], shouldContinue);
// [previousNode release];
//If it is the outputNode, [soundController newInputChain];
//else
endOfStream = YES;
}
amountToCopy = availInput;
if (availInput > amount)
if (amountToCopy > amount)
{
amountToCopy = amount;
}
@ -96,14 +107,9 @@
if (amountToCopy > 0)
{
[[previousNode buffer] didReadLength:amountToCopy];
[[previousNode semaphore] signal];
}
//Do endOfInput fun now...
if ((amountToCopy <= 0) && ([previousNode endOfInput] == YES))
{
endOfInput = YES;
shouldContinue = NO;
}
return amountToCopy;
}
@ -139,14 +145,14 @@
return semaphore;
}
- (BOOL)endOfInput
- (BOOL)endOfStream
{
return endOfInput;
return endOfStream;
}
- (void)setEndOfInput:(BOOL)e
- (void)setEndOfStream:(BOOL)e
{
endOfInput = e;
endOfStream = e;
}
@end

View File

@ -17,6 +17,7 @@
if (self)
{
outputController = c;
outputUnit = NULL;
}
return self;
@ -32,14 +33,24 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
if ([output->outputController shouldContinue] == NO)
{
NSLog(@"STOPPING");
AudioOutputUnitStop(output->outputUnit);
// [output stop];
return err;
}
amountToRead = inNumberFrames*(output->deviceFormat.mBytesPerPacket);
amountRead = [output->outputController readData:(readPointer) amount:amountToRead];
// NSLog(@"Amount read: %i %i", amountRead, [output->outputController endOfStream]);
if ((amountRead < amountToRead) && [output->outputController endOfStream] == NO) //Try one more time! for track changes!
{
int amountRead2; //Use this since return type of readdata isnt known...may want to fix then can do a simple += to readdata
amountRead2 = [output->outputController readData:(readPointer+amountRead) amount:amountToRead-amountRead];
amountRead += amountRead2;
}
// NSLog(@"Amount read: %i", amountRead);
ioData->mBuffers[0].mDataByteSize = amountRead;
return err;
@ -48,6 +59,9 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
- (BOOL)setup
{
NSLog(@"SETUP");
if (outputUnit)
[self stop];
ComponentDescription desc;
OSStatus err;
@ -154,6 +168,11 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
}
}
- (void)dealloc
{
[self stop];
}
- (void)pause
{
AudioOutputUnitStop(outputUnit);

View File

@ -1,5 +1,5 @@
//
// OutputController.h
// OutputNode.h
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
@ -18,13 +18,17 @@
@interface OutputNode : Node {
AudioStreamBasicDescription format;
int amountPlayed;
OutputCoreAudio *output;
}
- (id)initWithController:(id)c previousLink:p;
- (double)amountPlayed;
- (void)setup;
- (void)process;
- (void)close;
- (int)readData:(void *)ptr amount:(int)amount;

View File

@ -1,5 +1,5 @@
//
// OutputController.m
// OutputNode.m
// Cog
//
// Created by Zaphod Beeblebrox on 8/2/05.
@ -13,6 +13,8 @@
- (void)setup
{
amountPlayed = 0;
output = [[OutputCoreAudio alloc] initWithController:self];
[output setup];
@ -35,39 +37,37 @@
- (int)readData:(void *)ptr amount:(int)amount
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int n;
previousNode = [[controller bufferChain] finalNode];
n = [super readData:ptr amount:amount];
if ((n == 0) && (endOfInput == YES))
// NSLog(@"N: %i %i", n, endOfStream);
if (endOfStream == YES)
{
endOfInput = NO;
shouldContinue = YES;
NSLog(@"DONE IN");
return 0;
NSLog(@"End of stream reached: %i", endOfStream);
amountPlayed = 0;
[controller endOfInputPlayed]; //Updates shouldContinue appropriately?
NSLog(@"End of stream reached: %i", endOfStream);
// return (n + [self readData:ptr amount:(amount-n)]);
}
void *tempPtr;
if (([[[[controller bufferChain] finalNode] buffer] lengthAvailableToReadReturningPointer:&tempPtr] == 0) && ([[[controller bufferChain] finalNode] endOfInput] == YES))
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(@"END OF OUTPUT INPUT?!");
[controller endOfInputPlayed];
endOfInput = YES;
amountPlayed += n;
[pool release];
return n + [self readData:&ptr[n] amount:(amount-n)];
}
[pool release];
return n;
}
- (double)amountPlayed
{
return (amountPlayed/format.mBytesPerFrame)/(format.mSampleRate/1000.0);
}
- (AudioStreamBasicDescription) format
{
return format;
@ -78,6 +78,16 @@
format = *f;
}
- (void)close
{
[output stop];
}
- (void)dealloc
{
[output release];
}
- (void)setVolume:(double) v
{
[output setVolume:v];
@ -87,7 +97,7 @@
{
[super setShouldContinue:s];
if (s == NO)
[output stop];
// if (s == NO)
// [output stop];
}
@end

View File

@ -37,6 +37,9 @@
- (void)seekToTime:(double)time;
- (void)setVolume:(double)v;
- (double)amountPlayed;
- (void)setNextSong:(NSString *)s;
- (void)setPlaybackStatus:(int)s;

View File

@ -1,5 +1,5 @@
//
// Controller.m
// SoundController.m
// Cog
//
// Created by Zaphod Beeblebrox on 8/7/05.
@ -19,8 +19,8 @@
if (self)
{
//things
output = [[OutputNode alloc] initWithController:self previous:nil];
bufferChain = [[BufferChain alloc] initWithController:self];
output = NULL;
bufferChain = NULL;
chainQueue = [[NSMutableArray alloc] init];
@ -33,7 +33,28 @@
- (void)play:(NSString *)filename
{
DBLog(@"OPENING FILE: %s\n", filename);
if (output)
{
[output release];
}
output = [[OutputNode alloc] initWithController:self previous:nil];
[output setup];
NSEnumerator *enumerator = [chainQueue objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject])
{
[anObject setShouldContinue:NO];
}
[chainQueue removeAllObjects];
if (bufferChain)
{
[bufferChain setShouldContinue:NO];
[bufferChain release];
}
bufferChain = [[BufferChain alloc] initWithController:self];
[bufferChain open:filename];
[self setShouldContinue:YES];
@ -91,6 +112,11 @@
[output setShouldContinue:s];
}
- (double)amountPlayed
{
return [output amountPlayed];
}
- (void)endOfInputReached
{
[delegate delegateRequestNextSong:[chainQueue count]];
@ -117,7 +143,8 @@
if ([chainQueue count] <= 0)
{
//End of playlist
[self setPlaybackStatus:kCogStatusStopped];
NSLog(@"STOPPED");
[self stop];
return;
}
@ -130,14 +157,12 @@
[chainQueue removeObjectAtIndex:0];
NSLog(@"SONG CHANGED");
[delegate delegateNotifySongChanged:0.0];
// NSLog(@"SWAPPED");
[delegate delegateNotifySongChanged];
[output setEndOfStream:NO];
}
- (void)setPlaybackStatus:(int)s
{
{
[delegate performSelectorOnMainThread:@selector(delegateNotifyStatusUpdate:) withObject:[NSNumber numberWithInt:s] waitUntilDone:NO];
}