From bb9f463b52259cfe6b39ae5b5ec39c2764d2dbfd Mon Sep 17 00:00:00 2001 From: vspader Date: Wed, 7 Sep 2005 22:33:16 +0000 Subject: [PATCH] Added new files --- Changelog | 1 + Cog.xcodeproj/project.pbxproj | 32 ++++ Controller.h | 30 ++++ Controller.m | 14 ++ Converter.h | 22 +++ Converter.m | 111 ++++++++++++++ English.lproj/MainMenu.nib/info.nib | 4 +- English.lproj/MainMenu.nib/keyedobjects.nib | Bin 47031 -> 47046 bytes InputController.h | 17 +++ InputController.m | 19 +++ OutputController.h | 17 +++ OutputController.m | 14 ++ OutputCoreAudio.h | 20 +++ OutputCoreAudio.m | 158 ++++++++++++++++++++ Playlist/PlaylistEntry.m | 4 +- README | 2 +- Semaphore.h | 21 +++ Semaphore.m | 42 ++++++ Sound.h | 2 +- Sound.m | 9 +- 20 files changed, 530 insertions(+), 9 deletions(-) create mode 100644 Controller.h create mode 100644 Controller.m create mode 100644 Converter.h create mode 100644 Converter.m create mode 100644 InputController.h create mode 100644 InputController.m create mode 100644 OutputController.h create mode 100644 OutputController.m create mode 100644 OutputCoreAudio.h create mode 100644 OutputCoreAudio.m create mode 100644 Semaphore.h create mode 100644 Semaphore.m diff --git a/Changelog b/Changelog index 3d9d22399..ea6921ff4 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,7 @@ The playlist index now starts at 1. Seekbar now updates the time field as you drag it, Simon Savary French translation courtesy of Simon Savary Window is now brought to the front when opening a playlist. +Should work with 3rd party audio devices. 0.04 ---- diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index ae494479d..cae3f6555 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -197,6 +197,8 @@ 8E267D0C0837F7A6004ACBC5 /* UpdateController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UpdateController.m; sourceTree = ""; }; 8E2871080836934A0013CE39 /* VirtualRingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VirtualRingBuffer.h; sourceTree = ""; }; 8E2871090836934A0013CE39 /* VirtualRingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VirtualRingBuffer.m; sourceTree = ""; }; + 8E2C5C2D08A67867008DA854 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = ""; }; + 8E2C5C2E08A67867008DA854 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = ""; }; 8E45227A0832898A00F8BA7C /* Sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sound.h; sourceTree = ""; }; 8E45227B0832898A00F8BA7C /* Sound.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = Sound.m; sourceTree = ""; }; 8E47218508318D7A001F89FA /* DNDArrayController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNDArrayController.h; path = Playlist/DNDArrayController.h; sourceTree = ""; }; @@ -215,6 +217,16 @@ 8E546D6908843E8500E356EE /* French */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = French; path = French.lproj/Localizable.strings; sourceTree = ""; }; 8E5A90B0084CBC2F00AE6D62 /* Changelog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Changelog; sourceTree = ""; }; 8E6F2A1808480D010011F126 /* wheel.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = wheel.icns; path = Icons/wheel.icns; sourceTree = ""; }; + 8E7D4F0B08A0709C00EBB15A /* OutputCoreAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputCoreAudio.h; sourceTree = ""; }; + 8E7D4F0C08A0709C00EBB15A /* OutputCoreAudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputCoreAudio.m; sourceTree = ""; }; + 8E7D4F0F08A070AC00EBB15A /* OutputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputController.h; sourceTree = ""; }; + 8E7D4F1008A070AC00EBB15A /* OutputController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputController.m; sourceTree = ""; }; + 8E7D4F1308A070BB00EBB15A /* InputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputController.h; sourceTree = ""; }; + 8E7D4F1408A070BB00EBB15A /* InputController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InputController.m; sourceTree = ""; }; + 8E7D4F1808A070D600EBB15A /* Converter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Converter.h; sourceTree = ""; }; + 8E7D4F1908A070D600EBB15A /* Converter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Converter.m; sourceTree = ""; }; + 8E7D4F5A08A0734300EBB15A /* Semaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Semaphore.h; sourceTree = ""; }; + 8E7D4F5B08A0734300EBB15A /* Semaphore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Semaphore.m; sourceTree = ""; }; 8E7FA05508731B49005E8B5F /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; 8E7FA05908731B6F005E8B5F /* COMPILE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COMPILE; sourceTree = ""; }; 8E81BC31083673ED0025A375 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; @@ -313,6 +325,7 @@ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( + 8E7D4F0A08A0708600EBB15A /* New */, 8E267D030837F7A6004ACBC5 /* Feedback */, 8E267D080837F7A6004ACBC5 /* Updates */, 8E47215C08318D12001F89FA /* Playlist */, @@ -472,6 +485,25 @@ name = Custom; sourceTree = ""; }; + 8E7D4F0A08A0708600EBB15A /* New */ = { + isa = PBXGroup; + children = ( + 8E7D4F1808A070D600EBB15A /* Converter.h */, + 8E7D4F1908A070D600EBB15A /* Converter.m */, + 8E7D4F0B08A0709C00EBB15A /* OutputCoreAudio.h */, + 8E7D4F0C08A0709C00EBB15A /* OutputCoreAudio.m */, + 8E7D4F0F08A070AC00EBB15A /* OutputController.h */, + 8E7D4F1008A070AC00EBB15A /* OutputController.m */, + 8E7D4F1308A070BB00EBB15A /* InputController.h */, + 8E7D4F1408A070BB00EBB15A /* InputController.m */, + 8E7D4F5A08A0734300EBB15A /* Semaphore.h */, + 8E7D4F5B08A0734300EBB15A /* Semaphore.m */, + 8E2C5C2D08A67867008DA854 /* Controller.h */, + 8E2C5C2E08A67867008DA854 /* Controller.m */, + ); + name = New; + sourceTree = ""; + }; 8EAFD26D08465E4500107BA5 /* Icons */ = { isa = PBXGroup; children = ( diff --git a/Controller.h b/Controller.h new file mode 100644 index 000000000..8fe1b9f04 --- /dev/null +++ b/Controller.h @@ -0,0 +1,30 @@ +// +// Controller.h +// Cog +// +// Created by Zaphod Beeblebrox on 8/7/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface SoundController : NSObject { + InputController *input; + OutputController *output; + Converter *converter; + + NSLock *outputLock; + NSLock *inputLock; + + Semaphore *conversionSemaphore; + Semaphore *ioSemaphore; + + NSMutableArray *amountConverted; + unsigned int amountPlayed; //when amountPlayed > amountConverted[0], amountPlayed -= amountConverted[0], pop(amountConverted[0]) +} + +- (void)convertedAmount:(int)amount; //called by converter...same thread? +- (void)playedAmount:(int)amount; //called by outputcontroller...different thread + +@end diff --git a/Controller.m b/Controller.m new file mode 100644 index 000000000..696614178 --- /dev/null +++ b/Controller.m @@ -0,0 +1,14 @@ +// +// Controller.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/7/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "Controller.h" + + +@implementation SoundController + +@end diff --git a/Converter.h b/Converter.h new file mode 100644 index 000000000..03d6e9001 --- /dev/null +++ b/Converter.h @@ -0,0 +1,22 @@ +// +// Converter.h +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface Converter : NSObject { + SoundController *soundController; +} + +- (void)setup; +- (void)cleanUp; + +- (void)process; +- (int)convert:(void *)dest amount:(int)amount; + +@end diff --git a/Converter.m b/Converter.m new file mode 100644 index 000000000..ce5651e8b --- /dev/null +++ b/Converter.m @@ -0,0 +1,111 @@ +// +// Converter.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "Converter.h" + + +@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) +{ + SoundController *soundController = (SoundController *)inUserData; + OSStatus err = noErr; + + int amountToWrite; + int amountWritten; + + amountToWrite = (*ioNumberDataPackets)*[[soundController input] format].mBytesPerPacket; + + availInput = [[[soundController input] buffer] amountAvailableToReadReturningBuffer:&readPtr]; + while (availInput == 0) + { + [conversionSemaphore wait]; + + availInput = [[[soundController input] buffer] amountAvailableToReadReturningBuffer:&readPtr]; + } + + if (availInput > amountToWrite) + availInput = amountToWrite; + + *ioNumberDataPackets = availInput/format->mBytesPerPacket; + + ioData->mBuffers[0].mData = readPtr; + ioData->mBuffers[0].mDataByteSize = availInput; + ioData->mBuffers[0].mNumberChannels = [[soundController input] format].mChannelsPerFrame; + ioData->mNumberBuffers = 1; + + return err; +} + +-(void)process +{ + void *writePtr; + int availOutput; + int amountConverted; + + while ([soundController shouldContinue] == YES) + { + [[soundController outputLock] lock]; + availOutput = [[[soundController output] buffer] amountAvailableToWriteReturningBuffer:&writePtr]; + while (availOutput == 0) + { + [[soundController outputLock] unlock]; + [conversionSemaphore wait]; + + [[soundController outputLock] lock]; + availOutput = [[[soundController output] buffer] amountAvailableToWriteReturningBuffer:&writePtr]; + } + + amountConverted = [self convert:writePtr amount:availOutput]; + + [[[soundController output] buffer] didWriteAmount:amountConverted]; + [[soundController outputLock] unlock]; + } +} + +- (int)convert:(void *)dest amount:(int)amount +{ + AudioBufferList ioData; + UInt32 ioNumberFrames; + OSStatus err; + + ioNumberFrames = amount/[[soundController output] format].mBytesPerFrame; + ioData.mBuffers[0].mData = dest; + ioData.mBuffers[0].mDataByteSize = amount; + ioData.mBuffers[0].mNumberChannels = [[soundController output] format].mChannelsPerFrame; + ioData.mNumberBuffers = 1; + + err = AudioConverterFillComplexBuffer(converter, ACInputProc, &[[soundController input] format], &ioNumberFrames, &ioData, NULL); + if (err != noErr) + DBLog(@"Converter error: %i", err); + + [[soundController inputBuffer] didReadLength:(ioNumberFrames * [[[soundController input] format].mBytesPerFrame]); + [[soundController ioSemaphore] signal]; + + return ioData.mBuffers[0].mDataByteSize; +} + +- (void)setup +{ + //Make the converter + OSStatus stat = noErr; + stat = AudioConverterNew ( &sourceStreamFormat, &deviceFormat, &converter); + // DBLog(@"Created converter"); + if (stat != noErr) + { + DBLog(@"Error creating converter %i", stat); + } +} + +- (void)cleanUp +{ + AudioConverterDispose(converter); +} + +@end diff --git a/English.lproj/MainMenu.nib/info.nib b/English.lproj/MainMenu.nib/info.nib index 6a8ee18ea..d3caabdea 100644 --- a/English.lproj/MainMenu.nib/info.nib +++ b/English.lproj/MainMenu.nib/info.nib @@ -9,7 +9,7 @@ 29 243 676 346 44 0 0 1024 746 463 - 354 382 352 268 0 0 1024 746 + 336 385 352 268 0 0 1024 746 513 475 157 109 106 0 0 1024 746 @@ -28,8 +28,8 @@ 3 IBOpenObjects - 21 463 + 21 IBSystem Version 8C46 diff --git a/English.lproj/MainMenu.nib/keyedobjects.nib b/English.lproj/MainMenu.nib/keyedobjects.nib index 87a85d06135611ebdbef26132965020429380156..0d557588e97bb32ee6b49d955e0e122a24aace43 100644 GIT binary patch delta 25802 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 + + +@interface InputController : NSObject { + VirtualRingBuffer *buffer; + AudioStreamBasicDescription format; +} + +@end diff --git a/InputController.m b/InputController.m new file mode 100644 index 000000000..dda426d94 --- /dev/null +++ b/InputController.m @@ -0,0 +1,19 @@ +// +// InputController.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "InputController.h" + + +@implementation InputController + +- (void)play +{ + [SoundFile open:filename]; +} + +@end diff --git a/OutputController.h b/OutputController.h new file mode 100644 index 000000000..1a97c7c7b --- /dev/null +++ b/OutputController.h @@ -0,0 +1,17 @@ +// +// OutputController.h +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface OutputController : NSObject { + VirtualRingBuffer *buffer; + AudioStreamBasicDescription format; +} + +@end diff --git a/OutputController.m b/OutputController.m new file mode 100644 index 000000000..4370b9dea --- /dev/null +++ b/OutputController.m @@ -0,0 +1,14 @@ +// +// OutputController.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "OutputController.h" + + +@implementation OutputController + +@end diff --git a/OutputCoreAudio.h b/OutputCoreAudio.h new file mode 100644 index 000000000..afdaaaa6d --- /dev/null +++ b/OutputCoreAudio.h @@ -0,0 +1,20 @@ +// +// OutputCoreAudio.h +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface OutputCoreAudio : NSObject { + +} + +- (void)setup; +- (void)start; +- (void)stop; + +@end diff --git a/OutputCoreAudio.m b/OutputCoreAudio.m new file mode 100644 index 000000000..a3c219a9c --- /dev/null +++ b/OutputCoreAudio.m @@ -0,0 +1,158 @@ +// +// OutputCoreAudio.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "OutputCoreAudio.h" + + +@implementation OutputCoreAudio + +static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + Sound *sound = (Sound *)inRefCon; + OSStatus err = noErr; + + int amountAvailable; + int amountToRead; + void *readPointer; + + [sound->readLock lock]; + + amountAvailable = [sound->readRingBuffer lengthAvailableToReadReturningPointer:&readPointer]; + if (sound->playbackStatus == kCogStatusEndOfFile && amountAvailable == 0) + { + DBLog(@"FILE CHANGED!!!!!"); + [sound sendPortMessage:kCogFileChangedMessage]; + sound->readRingBuffer = [sound oppositeBuffer:sound->readRingBuffer]; + + [sound setPlaybackStatus:kCogStatusPlaying]; + + sound->currentPosition = 0; + + double time = [sound calculateTime:sound->totalLength]; + int bitrate = [sound->soundFile bitRate]; + [sound sendPortMessage:kCogLengthUpdateMessage withData:&time ofSize:(sizeof(double))]; + [sound sendPortMessage:kCogBitrateUpdateMessage withData:&bitrate ofSize:(sizeof(int))]; + } + if (sound->playbackStatus == kCogStatusEndOfPlaylist && amountAvailable == 0) + { + //Stop playback + [sound setPlaybackStatus:kCogStatusStopped]; + // return err; + } + + if (amountAvailable < ([sound->readRingBuffer bufferLength] - BUFFER_WRITE_CHUNK)) + { + // DBLog(@"AVAILABLE: %i", amountAvailable); + [sound fireFillTimer]; + } + + if (amountAvailable > inNumberFrames*sound->deviceFormat.mBytesPerPacket) + amountToRead = inNumberFrames*sound->deviceFormat.mBytesPerPacket; + else + amountToRead = amountAvailable; + + memcpy(ioData->mBuffers[0].mData, readPointer, amountToRead); + ioData->mBuffers[0].mDataByteSize = amountToRead; + + [sound->readRingBuffer didReadLength:amountToRead]; + + sound->currentPosition += amountToRead; + + [sound->readLock unlock]; + + return err; +} + +- (void)setup +{ + ComponentDescription desc; + OSStatus err; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + Component comp = FindNextComponent(NULL, &desc); //Finds an component that meets the desc spec's + if (comp == NULL) + return NO; + + err = OpenAComponent(comp, &outputUnit); //gains access to the services provided by the component + if (err) + return NO; + + // Initialize AudioUnit + err = AudioUnitInitialize(outputUnit); + if (err != noErr) + return NO; + + + UInt32 size = sizeof (AudioStreamBasicDescription); + Boolean outWritable; + //Gets the size of the Stream Format Property and if it is writable + AudioUnitGetPropertyInfo(outputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, + &size, + &outWritable); + //Get the current stream format of the output + err = AudioUnitGetProperty (outputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, + &deviceFormat, + &size); + + if (err != noErr) + return NO; + + // change output format... + ///Seems some 3rd party devices return incorrect stuff...or I just don't like noninterleaved data. + deviceFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + deviceFormat.mBytesPerFrame = deviceFormat.mChannelsPerFrame*(deviceFormat.mBitsPerChannel/8); + deviceFormat.mBytesPerPacket = deviceFormat.mBytesPerFrame * deviceFormat.mFramesPerPacket; + // DBLog(@"stuff: %i %i %i %i", deviceFormat.mBitsPerChannel, deviceFormat.mBytesPerFrame, deviceFormat.mBytesPerPacket, deviceFormat.mFramesPerPacket); + err = AudioUnitSetProperty (outputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, + &deviceFormat, + size); + + //Set the stream format of the output to match the input + err = AudioUnitSetProperty (outputUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &deviceFormat, + size); + + //setup render callbacks + renderCallback.inputProc = Sound_Renderer; + renderCallback.inputProcRefCon = self; + + AudioUnitSetProperty(outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct)); + + // DBLog(@"Audio output successfully initialized"); + return (err == noErr); +} + +- (void)start +{ + AudioOutputUnitStart(outputUnit); +} + +- (void)stop +{ + if (outputUnit) + AudioOutputUnitStop(outputUnit); +} + +@end diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index 61c6c79aa..64875c9a3 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -219,10 +219,12 @@ -(void)readTags { TagLib_File *tagFile = taglib_file_new((const char *)[filename UTF8String]); + NSLog(@"Does it have a file? %i %s", tagFile, (const char *)[filename UTF8String]); if (tagFile) { TagLib_Tag *tag = taglib_file_tag(tagFile); - + NSLog(@"Does it have a tag? %i", tag); + if (tag) { char *pArtist, *pTitle, *pAlbum, *pGenre, *pComment; diff --git a/README b/README index bb2e80cc7..31ba20304 100644 --- a/README +++ b/README @@ -19,7 +19,7 @@ licenses. It is rated M for mature by the ESRB, the MPAA, and whatever else deems it unsuitable for virgin ears. - All Cog code is copywrited by me, and is licensed under the GPL. + All Cog code is copyrighted by me, and is licensed under the GPL. If you would like the photoshop sources for the various icons and graphics, please send me an email, and I will be happy to get them to you. diff --git a/Semaphore.h b/Semaphore.h new file mode 100644 index 000000000..632c8c2dd --- /dev/null +++ b/Semaphore.h @@ -0,0 +1,21 @@ +// +// Semaphore.h +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import +#import + +@interface Semaphore : NSObject { + semaphore_t semaphore; +} + +-(id)init; +-(void)signal; +-(void)timedWait:(int)seconds; +-(void)wait; + +@end diff --git a/Semaphore.m b/Semaphore.m new file mode 100644 index 000000000..c35d7677e --- /dev/null +++ b/Semaphore.m @@ -0,0 +1,42 @@ +// +// Semaphore.m +// Cog +// +// Created by Zaphod Beeblebrox on 8/2/05. +// Copyright 2005 __MyCompanyName__. All rights reserved. +// + +#import "Semaphore.h" + + +@implementation Semaphore + +-(id)init +{ + self = [super init]; + if (self) + { + semaphore_create(mach_task_self(), &semaphore, SYNC_POLICY_FIFO, 0); + } + + return self; +} + +-(void)signal +{ + semaphore_signal(semaphore); +} + +-(void)timedWait:(int)seconds +{ + mach_timespec_t timeout = {seconds, 0}; + + semaphore_timedwait(semaphore, timeout); +} + +-(void)wait +{ + semaphore_wait(semaphore); +} + +@end diff --git a/Sound.h b/Sound.h index 17634fac9..655f41a7d 100644 --- a/Sound.h +++ b/Sound.h @@ -102,7 +102,7 @@ enum - (void)resetBuffer; - (VirtualRingBuffer *)oppositeBuffer:(VirtualRingBuffer *)buf; -//private methodss +//private methods - (BOOL)setupAudioOutput; - (BOOL)startAudioOutput; - (void)stopAudioOutput; diff --git a/Sound.m b/Sound.m index 6c3469d84..84c8be992 100644 --- a/Sound.m +++ b/Sound.m @@ -137,6 +137,9 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc sound->currentPosition += amountToRead; + if (sound->currentPosition > 1764000) + [sound stop]; + [sound->readLock unlock]; return err; @@ -689,8 +692,6 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc return; } - DBLog(@"DONT LIKE THIS, HUH?"); - [readLock lock]; unsigned long length = totalLength; int bitrate = [soundFile bitRate]; @@ -718,7 +719,7 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc - (void)resetBuffer { [writeLock lock]; - [readLock lock]; +// [readLock lock]; [ringBuffer empty]; [auxRingBuffer empty]; @@ -728,7 +729,7 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc currentPosition = 0; - [readLock unlock]; +// [readLock unlock]; [writeLock unlock]; }