Added new files
parent
91957a3d72
commit
bb9f463b52
|
@ -11,6 +11,7 @@ The playlist index now starts at 1.
|
||||||
Seekbar now updates the time field as you drag it, Simon Savary <savary (at) oricom.ca>
|
Seekbar now updates the time field as you drag it, Simon Savary <savary (at) oricom.ca>
|
||||||
French translation courtesy of Simon Savary <savary (at) oricom.ca>
|
French translation courtesy of Simon Savary <savary (at) oricom.ca>
|
||||||
Window is now brought to the front when opening a playlist.
|
Window is now brought to the front when opening a playlist.
|
||||||
|
Should work with 3rd party audio devices.
|
||||||
|
|
||||||
0.04
|
0.04
|
||||||
----
|
----
|
||||||
|
|
|
@ -197,6 +197,8 @@
|
||||||
8E267D0C0837F7A6004ACBC5 /* UpdateController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UpdateController.m; sourceTree = "<group>"; };
|
8E267D0C0837F7A6004ACBC5 /* UpdateController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UpdateController.m; sourceTree = "<group>"; };
|
||||||
8E2871080836934A0013CE39 /* VirtualRingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VirtualRingBuffer.h; sourceTree = "<group>"; };
|
8E2871080836934A0013CE39 /* VirtualRingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VirtualRingBuffer.h; sourceTree = "<group>"; };
|
||||||
8E2871090836934A0013CE39 /* VirtualRingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VirtualRingBuffer.m; sourceTree = "<group>"; };
|
8E2871090836934A0013CE39 /* VirtualRingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = VirtualRingBuffer.m; sourceTree = "<group>"; };
|
||||||
|
8E2C5C2D08A67867008DA854 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
||||||
|
8E2C5C2E08A67867008DA854 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
||||||
8E45227A0832898A00F8BA7C /* Sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sound.h; sourceTree = "<group>"; };
|
8E45227A0832898A00F8BA7C /* Sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sound.h; sourceTree = "<group>"; };
|
||||||
8E45227B0832898A00F8BA7C /* Sound.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = Sound.m; sourceTree = "<group>"; };
|
8E45227B0832898A00F8BA7C /* Sound.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = Sound.m; sourceTree = "<group>"; };
|
||||||
8E47218508318D7A001F89FA /* DNDArrayController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNDArrayController.h; path = Playlist/DNDArrayController.h; sourceTree = "<group>"; };
|
8E47218508318D7A001F89FA /* DNDArrayController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNDArrayController.h; path = Playlist/DNDArrayController.h; sourceTree = "<group>"; };
|
||||||
|
@ -215,6 +217,16 @@
|
||||||
8E546D6908843E8500E356EE /* French */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = French; path = French.lproj/Localizable.strings; sourceTree = "<group>"; };
|
8E546D6908843E8500E356EE /* French */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = French; path = French.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
8E5A90B0084CBC2F00AE6D62 /* Changelog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Changelog; sourceTree = "<group>"; };
|
8E5A90B0084CBC2F00AE6D62 /* Changelog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Changelog; sourceTree = "<group>"; };
|
||||||
8E6F2A1808480D010011F126 /* wheel.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = wheel.icns; path = Icons/wheel.icns; sourceTree = "<group>"; };
|
8E6F2A1808480D010011F126 /* wheel.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = wheel.icns; path = Icons/wheel.icns; sourceTree = "<group>"; };
|
||||||
|
8E7D4F0B08A0709C00EBB15A /* OutputCoreAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputCoreAudio.h; sourceTree = "<group>"; };
|
||||||
|
8E7D4F0C08A0709C00EBB15A /* OutputCoreAudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputCoreAudio.m; sourceTree = "<group>"; };
|
||||||
|
8E7D4F0F08A070AC00EBB15A /* OutputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputController.h; sourceTree = "<group>"; };
|
||||||
|
8E7D4F1008A070AC00EBB15A /* OutputController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputController.m; sourceTree = "<group>"; };
|
||||||
|
8E7D4F1308A070BB00EBB15A /* InputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputController.h; sourceTree = "<group>"; };
|
||||||
|
8E7D4F1408A070BB00EBB15A /* InputController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InputController.m; sourceTree = "<group>"; };
|
||||||
|
8E7D4F1808A070D600EBB15A /* Converter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Converter.h; sourceTree = "<group>"; };
|
||||||
|
8E7D4F1908A070D600EBB15A /* Converter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Converter.m; sourceTree = "<group>"; };
|
||||||
|
8E7D4F5A08A0734300EBB15A /* Semaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Semaphore.h; sourceTree = "<group>"; };
|
||||||
|
8E7D4F5B08A0734300EBB15A /* Semaphore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Semaphore.m; sourceTree = "<group>"; };
|
||||||
8E7FA05508731B49005E8B5F /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
|
8E7FA05508731B49005E8B5F /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
|
||||||
8E7FA05908731B6F005E8B5F /* COMPILE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COMPILE; sourceTree = "<group>"; };
|
8E7FA05908731B6F005E8B5F /* COMPILE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COMPILE; sourceTree = "<group>"; };
|
||||||
8E81BC31083673ED0025A375 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<absolute>"; };
|
8E81BC31083673ED0025A375 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<absolute>"; };
|
||||||
|
@ -313,6 +325,7 @@
|
||||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8E7D4F0A08A0708600EBB15A /* New */,
|
||||||
8E267D030837F7A6004ACBC5 /* Feedback */,
|
8E267D030837F7A6004ACBC5 /* Feedback */,
|
||||||
8E267D080837F7A6004ACBC5 /* Updates */,
|
8E267D080837F7A6004ACBC5 /* Updates */,
|
||||||
8E47215C08318D12001F89FA /* Playlist */,
|
8E47215C08318D12001F89FA /* Playlist */,
|
||||||
|
@ -472,6 +485,25 @@
|
||||||
name = Custom;
|
name = Custom;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
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 = "<group>";
|
||||||
|
};
|
||||||
8EAFD26D08465E4500107BA5 /* Icons */ = {
|
8EAFD26D08465E4500107BA5 /* Icons */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Controller.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/7/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@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
|
|
@ -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
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// Converter.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface Converter : NSObject {
|
||||||
|
SoundController *soundController;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setup;
|
||||||
|
- (void)cleanUp;
|
||||||
|
|
||||||
|
- (void)process;
|
||||||
|
- (int)convert:(void *)dest amount:(int)amount;
|
||||||
|
|
||||||
|
@end
|
|
@ -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
|
|
@ -9,7 +9,7 @@
|
||||||
<key>29</key>
|
<key>29</key>
|
||||||
<string>243 676 346 44 0 0 1024 746 </string>
|
<string>243 676 346 44 0 0 1024 746 </string>
|
||||||
<key>463</key>
|
<key>463</key>
|
||||||
<string>354 382 352 268 0 0 1024 746 </string>
|
<string>336 385 352 268 0 0 1024 746 </string>
|
||||||
<key>513</key>
|
<key>513</key>
|
||||||
<string>475 157 109 106 0 0 1024 746 </string>
|
<string>475 157 109 106 0 0 1024 746 </string>
|
||||||
</dict>
|
</dict>
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
<integer>3</integer>
|
<integer>3</integer>
|
||||||
<key>IBOpenObjects</key>
|
<key>IBOpenObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>21</integer>
|
|
||||||
<integer>463</integer>
|
<integer>463</integer>
|
||||||
|
<integer>21</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>8C46</string>
|
<string>8C46</string>
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// InputController.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface InputController : NSObject {
|
||||||
|
VirtualRingBuffer *buffer;
|
||||||
|
AudioStreamBasicDescription format;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -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
|
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// OutputController.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface OutputController : NSObject {
|
||||||
|
VirtualRingBuffer *buffer;
|
||||||
|
AudioStreamBasicDescription format;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -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
|
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// OutputCoreAudio.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface OutputCoreAudio : NSObject {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setup;
|
||||||
|
- (void)start;
|
||||||
|
- (void)stop;
|
||||||
|
|
||||||
|
@end
|
|
@ -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
|
|
@ -219,9 +219,11 @@
|
||||||
-(void)readTags
|
-(void)readTags
|
||||||
{
|
{
|
||||||
TagLib_File *tagFile = taglib_file_new((const char *)[filename UTF8String]);
|
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)
|
if (tagFile)
|
||||||
{
|
{
|
||||||
TagLib_Tag *tag = taglib_file_tag(tagFile);
|
TagLib_Tag *tag = taglib_file_tag(tagFile);
|
||||||
|
NSLog(@"Does it have a tag? %i", tag);
|
||||||
|
|
||||||
if (tag)
|
if (tag)
|
||||||
{
|
{
|
||||||
|
|
2
README
2
README
|
@ -19,7 +19,7 @@ licenses.
|
||||||
It is rated M for mature by the ESRB, the MPAA, and whatever else deems it
|
It is rated M for mature by the ESRB, the MPAA, and whatever else deems it
|
||||||
unsuitable for virgin ears.
|
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
|
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.
|
graphics, please send me an email, and I will be happy to get them to you.
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Semaphore.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Zaphod Beeblebrox on 8/2/05.
|
||||||
|
// Copyright 2005 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <mach/mach.h>
|
||||||
|
|
||||||
|
@interface Semaphore : NSObject {
|
||||||
|
semaphore_t semaphore;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(id)init;
|
||||||
|
-(void)signal;
|
||||||
|
-(void)timedWait:(int)seconds;
|
||||||
|
-(void)wait;
|
||||||
|
|
||||||
|
@end
|
|
@ -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
|
2
Sound.h
2
Sound.h
|
@ -102,7 +102,7 @@ enum
|
||||||
- (void)resetBuffer;
|
- (void)resetBuffer;
|
||||||
- (VirtualRingBuffer *)oppositeBuffer:(VirtualRingBuffer *)buf;
|
- (VirtualRingBuffer *)oppositeBuffer:(VirtualRingBuffer *)buf;
|
||||||
|
|
||||||
//private methodss
|
//private methods
|
||||||
- (BOOL)setupAudioOutput;
|
- (BOOL)setupAudioOutput;
|
||||||
- (BOOL)startAudioOutput;
|
- (BOOL)startAudioOutput;
|
||||||
- (void)stopAudioOutput;
|
- (void)stopAudioOutput;
|
||||||
|
|
9
Sound.m
9
Sound.m
|
@ -137,6 +137,9 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
||||||
|
|
||||||
sound->currentPosition += amountToRead;
|
sound->currentPosition += amountToRead;
|
||||||
|
|
||||||
|
if (sound->currentPosition > 1764000)
|
||||||
|
[sound stop];
|
||||||
|
|
||||||
[sound->readLock unlock];
|
[sound->readLock unlock];
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -689,8 +692,6 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBLog(@"DONT LIKE THIS, HUH?");
|
|
||||||
|
|
||||||
[readLock lock];
|
[readLock lock];
|
||||||
unsigned long length = totalLength;
|
unsigned long length = totalLength;
|
||||||
int bitrate = [soundFile bitRate];
|
int bitrate = [soundFile bitRate];
|
||||||
|
@ -718,7 +719,7 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
||||||
- (void)resetBuffer
|
- (void)resetBuffer
|
||||||
{
|
{
|
||||||
[writeLock lock];
|
[writeLock lock];
|
||||||
[readLock lock];
|
// [readLock lock];
|
||||||
|
|
||||||
[ringBuffer empty];
|
[ringBuffer empty];
|
||||||
[auxRingBuffer empty];
|
[auxRingBuffer empty];
|
||||||
|
@ -728,7 +729,7 @@ static OSStatus Sound_Renderer(void *inRefCon, AudioUnitRenderActionFlags *ioAc
|
||||||
|
|
||||||
currentPosition = 0;
|
currentPosition = 0;
|
||||||
|
|
||||||
[readLock unlock];
|
// [readLock unlock];
|
||||||
[writeLock unlock];
|
[writeLock unlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue