Skip to content

Commit

Permalink
[WIP] working on more complete interface
Browse files Browse the repository at this point in the history
  • Loading branch information
ndonald2 committed Jun 12, 2013
1 parent f4572b0 commit 5d46854
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 44 deletions.
4 changes: 4 additions & 0 deletions Novocaine.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,7 @@
objects = { objects = {


/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
9AE2143E1768D0C60068A4DC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AE2143D1768D0C60068A4DC /* AVFoundation.framework */; };
FA0B92E9154ACB100079834E /* AudioFileReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA0B92E8154ACB100079834E /* AudioFileReader.mm */; }; FA0B92E9154ACB100079834E /* AudioFileReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA0B92E8154ACB100079834E /* AudioFileReader.mm */; };
FA0B92EA154ACB100079834E /* AudioFileReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA0B92E8154ACB100079834E /* AudioFileReader.mm */; }; FA0B92EA154ACB100079834E /* AudioFileReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA0B92E8154ACB100079834E /* AudioFileReader.mm */; };
FA2015DD154B02CC00F8D3AC /* TLC.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = FA2015DC154B02CC00F8D3AC /* TLC.mp3 */; }; FA2015DD154B02CC00F8D3AC /* TLC.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = FA2015DC154B02CC00F8D3AC /* TLC.mp3 */; };
Expand Down Expand Up @@ -42,6 +43,7 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */


/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
9AE2143D1768D0C60068A4DC /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
FA0B92E7154ACB100079834E /* AudioFileReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioFileReader.h; sourceTree = "<group>"; }; FA0B92E7154ACB100079834E /* AudioFileReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioFileReader.h; sourceTree = "<group>"; };
FA0B92E8154ACB100079834E /* AudioFileReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioFileReader.mm; sourceTree = "<group>"; }; FA0B92E8154ACB100079834E /* AudioFileReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioFileReader.mm; sourceTree = "<group>"; };
FA2015DC154B02CC00F8D3AC /* TLC.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = TLC.mp3; sourceTree = "<group>"; }; FA2015DC154B02CC00F8D3AC /* TLC.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = TLC.mp3; sourceTree = "<group>"; };
Expand Down Expand Up @@ -105,6 +107,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
9AE2143E1768D0C60068A4DC /* AVFoundation.framework in Frameworks */,
FA5526EF152A6466003D9601 /* Accelerate.framework in Frameworks */, FA5526EF152A6466003D9601 /* Accelerate.framework in Frameworks */,
FA5526F0152A6466003D9601 /* AudioToolbox.framework in Frameworks */, FA5526F0152A6466003D9601 /* AudioToolbox.framework in Frameworks */,
FA5526F2152A6466003D9601 /* CoreAudio.framework in Frameworks */, FA5526F2152A6466003D9601 /* CoreAudio.framework in Frameworks */,
Expand Down Expand Up @@ -146,6 +149,7 @@
FA55269E152A6405003D9601 /* AudioToolbox.framework */, FA55269E152A6405003D9601 /* AudioToolbox.framework */,
FA5526ED152A6466003D9601 /* AudioUnit.framework */, FA5526ED152A6466003D9601 /* AudioUnit.framework */,
FA55269F152A6405003D9601 /* AudioUnit.framework */, FA55269F152A6405003D9601 /* AudioUnit.framework */,
9AE2143D1768D0C60068A4DC /* AVFoundation.framework */,
FA5526EE152A6466003D9601 /* CoreAudio.framework */, FA5526EE152A6466003D9601 /* CoreAudio.framework */,
FA5526A0152A6405003D9601 /* CoreAudio.framework */, FA5526A0152A6405003D9601 /* CoreAudio.framework */,
FA55263B152A63A4003D9601 /* CoreGraphics.framework */, FA55263B152A63A4003D9601 /* CoreGraphics.framework */,
Expand Down
5 changes: 3 additions & 2 deletions Novocaine/AudioFileReader.h
Expand Up @@ -32,23 +32,24 @@


@property (nonatomic, assign, getter=getCurrentTime, setter=setCurrentTime:) float currentTime; @property (nonatomic, assign, getter=getCurrentTime, setter=setCurrentTime:) float currentTime;
@property (nonatomic, copy) NovocaineInputBlock readerBlock; @property (nonatomic, copy) NovocaineInputBlock readerBlock;
@property (nonatomic, assign) float latency;


// ----- Read-only ------ // ----- Read-only ------


@property (nonatomic, copy, readonly) NSURL *audioFileURL; @property (nonatomic, copy, readonly) NSURL *audioFileURL;
@property (nonatomic, assign, readonly, getter=getDuration) float duration; @property (nonatomic, assign, readonly, getter=getDuration) float duration;
@property (nonatomic, assign, readonly) float samplingRate; @property (nonatomic, assign, readonly) float samplingRate;
@property (nonatomic, assign, readonly) UInt32 numChannels; @property (nonatomic, assign, readonly) UInt32 numChannels;
@property (nonatomic, assign, readonly) float latency;
@property (nonatomic, assign, readonly) BOOL playing; @property (nonatomic, assign, readonly) BOOL playing;




- (id)initWithAudioFileURL:(NSURL *)urlToAudioFile samplingRate:(float)thisSamplingRate numChannels:(UInt32)thisNumChannels; - (id)initWithAudioFileURL:(NSURL *)urlToAudioFile samplingRate:(float)thisSamplingRate numChannels:(UInt32)thisNumChannels;


// You use this method to grab audio if you have your own callback. // You use this method to grab audio if you have your own callback.
// The buffer'll fill at the speed the audio is normally being played. // The buffer'll fill at the speed the audio is normally being played.

- (void)retrieveFreshAudio:(float *)buffer numFrames:(UInt32)thisNumFrames numChannels:(UInt32)thisNumChannels; - (void)retrieveFreshAudio:(float *)buffer numFrames:(UInt32)thisNumFrames numChannels:(UInt32)thisNumChannels;
//- (float)getCurrentTime;
- (void)play; - (void)play;
- (void)pause; - (void)pause;
- (void)stop; - (void)stop;
Expand Down
2 changes: 0 additions & 2 deletions Novocaine/AudioFileReader.mm
Expand Up @@ -37,7 +37,6 @@ @interface AudioFileReader ()
@property (nonatomic, assign, readwrite, getter=getDuration) float duration; @property (nonatomic, assign, readwrite, getter=getDuration) float duration;
@property (nonatomic, assign, readwrite) float samplingRate; @property (nonatomic, assign, readwrite) float samplingRate;
@property (nonatomic, assign, readwrite) UInt32 numChannels; @property (nonatomic, assign, readwrite) UInt32 numChannels;
@property (nonatomic, assign, readwrite) float latency;
@property (nonatomic, assign, readwrite) BOOL playing; @property (nonatomic, assign, readwrite) BOOL playing;


@property (nonatomic, assign) AudioStreamBasicDescription outputFormat; @property (nonatomic, assign) AudioStreamBasicDescription outputFormat;
Expand Down Expand Up @@ -215,7 +214,6 @@ - (float)getDuration


- (void)configureReaderCallback - (void)configureReaderCallback
{ {

if (!self.callbackTimer) if (!self.callbackTimer)
{ {
self.callbackTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); self.callbackTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
Expand Down
2 changes: 2 additions & 0 deletions Novocaine/Novocaine.h
Expand Up @@ -30,6 +30,7 @@
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
#else #else
#define USING_IOS #define USING_IOS
#include <AVFoundation/AVFoundation.h>
#endif #endif


#include <Block.h> #include <Block.h>
Expand Down Expand Up @@ -101,6 +102,7 @@ typedef void (^NovocaineInputBlock)(float *data, UInt32 numFrames, UInt32 numCha
// ------ These properties/methods are used for configuration ------- // ------ These properties/methods are used for configuration -------


@property (nonatomic, copy) NSString *inputRoute; @property (nonatomic, copy) NSString *inputRoute;
@property (nonatomic, assign) BOOL inputEnabled;


// ND: Exposing the block setters this way will create the correct block signature for auto-complete. // ND: Exposing the block setters this way will create the correct block signature for auto-complete.
// These will map to "copy" property setters in class continuation in source file // These will map to "copy" property setters in class continuation in source file
Expand Down
143 changes: 103 additions & 40 deletions Novocaine/Novocaine.m
Expand Up @@ -74,8 +74,9 @@ @interface Novocaine()
- (void)enumerateAudioDevices; - (void)enumerateAudioDevices;
#endif #endif


- (void)setupAudio; // must be called prior to playing audio
- (void)ifAudioInputIsAvailableThenSetupAudioSession; - (void)setupAudioSession;
- (void)setupAudioUnits;


- (NSString *)applicationDocumentsDirectory; - (NSString *)applicationDocumentsDirectory;


Expand Down Expand Up @@ -135,7 +136,7 @@ - (id)init
// self.playThroughEnabled = NO; // self.playThroughEnabled = NO;


// Fire up the audio session ( with steady error checking ... ) // Fire up the audio session ( with steady error checking ... )
[self ifAudioInputIsAvailableThenSetupAudioSession]; [self setupAudioSession];


return self; return self;


Expand Down Expand Up @@ -174,12 +175,81 @@ - (void)freeBuffers
} }
} }


#pragma mark - Properties

- (void)setInputEnabled:(BOOL)inputEnabled
{
if (inputEnabled != _inputEnabled){

if (inputEnabled){

if (self.inputAvailable) {

// Enable input
UInt32 one = 1;
OSStatus err = AudioUnitSetProperty(_inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&one,
sizeof(one));

if (err){

}
else{
_inputEnabled = YES;
}
}

// If we don't have input, then ask the user to provide some
else
{

// TODO: Not sure a
#if defined ( USING_IOS )
UIAlertView *noInputAlert =
[[UIAlertView alloc] initWithTitle:@"No Audio Input"
message:@"Couldn't find any audio input. Plug in your Apple headphones or another microphone."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];

[noInputAlert show];
#endif

}
}
else
{
// Disable input
UInt32 zero = 0;
OSStatus err = AudioUnitSetProperty(_inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&zero,
sizeof(zero));

if (err){

}
else{
_inputEnabled = NO;
}
}

}
}



#pragma mark - Audio Methods #pragma mark - Audio Methods




- (void)ifAudioInputIsAvailableThenSetupAudioSession { - (void)setupAudioSession
// Initialize and configure the audio session, and add an interuption listener {

// Initialize and configure the audio session, and add an interuption listener


#if defined ( USING_IOS ) #if defined ( USING_IOS )
CheckError( AudioSessionInitialize(NULL, NULL, sessionInterruptionListener, (__bridge void *)(self)), "Couldn't initialize audio session"); CheckError( AudioSessionInitialize(NULL, NULL, sessionInterruptionListener, (__bridge void *)(self)), "Couldn't initialize audio session");
Expand All @@ -189,39 +259,37 @@ - (void)ifAudioInputIsAvailableThenSetupAudioSession {
[self enumerateAudioDevices]; [self enumerateAudioDevices];
self.inputAvailable = YES; self.inputAvailable = YES;
#endif #endif



// Check the session properties (available input routes, number of channels, etc) // Check the session properties (available input routes, number of channels, etc)




// If we do have input, then let's rock 'n roll. // If we do have input, then let's rock 'n roll.
if (self.inputAvailable) { // if (self.inputAvailable) {
[self setupAudio]; // [self setupAudio];
[self play]; // [self play];
} // }

//
// If we don't have input, then ask the user to provide some // // If we don't have input, then ask the user to provide some
else // else
{ // {
#if defined ( USING_IOS ) //#if defined ( USING_IOS )
UIAlertView *noInputAlert = // UIAlertView *noInputAlert =
[[UIAlertView alloc] initWithTitle:@"No Audio Input" // [[UIAlertView alloc] initWithTitle:@"No Audio Input"
message:@"Couldn't find any audio input. Plug in your Apple headphones or another microphone." // message:@"Couldn't find any audio input. Plug in your Apple headphones or another microphone."
delegate:self // delegate:self
cancelButtonTitle:@"OK" // cancelButtonTitle:@"OK"
otherButtonTitles:nil]; // otherButtonTitles:nil];

//
[noInputAlert show]; // [noInputAlert show];
#endif //#endif

//
} // }
} }




- (void)setupAudio - (void)setupAudioUnits
{ {



// --- Audio Session Setup --- // --- Audio Session Setup ---
// --------------------------- // ---------------------------


Expand All @@ -245,7 +313,11 @@ - (void)setupAudio




// Set the audio session active // Set the audio session active
CheckError( AudioSessionSetActive(YES), "Couldn't activate the audio session"); NSError *err = nil;
if (![[AVAudioSession sharedInstance] setActive:YES error:&err]){
NSLog(@"Couldn't activate audio session: %@", err);
}



[self checkSessionProperties]; [self checkSessionProperties];


Expand Down Expand Up @@ -294,15 +366,6 @@ - (void)setupAudio
#endif #endif




// Enable input
UInt32 one = 1;
CheckError( AudioUnitSetProperty(_inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&one,
sizeof(one)), "Couldn't enable IO on the input scope of output unit");

#if defined ( USING_OSX ) #if defined ( USING_OSX )
// Disable output on the input unit // Disable output on the input unit
// (only on Mac, since on the iPhone, the input unit is also the output unit) // (only on Mac, since on the iPhone, the input unit is also the output unit)
Expand Down Expand Up @@ -663,7 +726,6 @@ - (void)play {


#endif #endif



self.inputAvailable = isInputAvailable; self.inputAvailable = isInputAvailable;


if ( self.inputAvailable ) { if ( self.inputAvailable ) {
Expand Down Expand Up @@ -762,6 +824,7 @@ OSStatus renderCallback (void *inRefCon,
UInt32 inNumberFrames, UInt32 inNumberFrames,
AudioBufferList * ioData) AudioBufferList * ioData)
{ {
// autorelease pool for much faster ARC performance on repeated calls from separate thread
@autoreleasepool { @autoreleasepool {


Novocaine *sm = (__bridge Novocaine *)inRefCon; Novocaine *sm = (__bridge Novocaine *)inRefCon;
Expand Down

0 comments on commit 5d46854

Please sign in to comment.