Compare commits

...

16 Commits

Author SHA1 Message Date
Syed Haris Ali ab9fb5b9bd bumped podspec and README to 0.4.0 and removed getting started reference (moving all to github) 2015-06-29 19:43:46 -07:00
Syed Haris Ali f98d520efd Merge pull request #171 from syedhali/output_rewrite
Rewrote EZOutput using AUGraph
2015-06-29 19:41:54 -07:00
Syed Haris Ali 6a44909a2f Used EZOutputDelegate for audio received callback and fixed minor bgs 2015-06-29 19:33:24 -07:00
Syed Haris Ali c85d1d9d2f so much documentation 2015-06-29 19:13:01 -07:00
Syed Haris Ali d03a5f76e6 added lots of documentation 2015-06-29 19:09:52 -07:00
Syed Haris Ali 6d7625027f added more documentation and pan property 2015-06-29 18:42:47 -07:00
Syed Haris Ali cce5ee0af1 minor tweak 2015-06-29 18:26:31 -07:00
Syed Haris Ali cc868e79dd little style tweak 2015-06-29 18:15:27 -07:00
Syed Haris Ali d2ad3d2034 added clean up for float converter 2015-06-29 18:14:10 -07:00
Syed Haris Ali 3fdb33209d added float converter 2015-06-29 18:11:56 -07:00
Syed Haris Ali e16c775be8 fixed broken IB connection 2015-06-29 17:52:45 -07:00
Syed Haris Ali 59a3a22c6a added plot clear 2015-06-29 17:51:53 -07:00
Syed Haris Ali 4c7719f168 added output selector to OSX play file example 2015-06-29 17:47:10 -07:00
Syed Haris Ali 5789954cb9 updated examples that explicitly use EZOuput and added volume controls 2015-06-29 17:32:03 -07:00
Syed Haris Ali c34c7c9f89 added documentation for Core Audio properties 2015-06-29 16:28:20 -07:00
Syed Haris Ali 6745265dd5 rewrote EZOuput and added output device support for iOS and OSX 2015-06-29 16:17:08 -07:00
18 changed files with 1386 additions and 584 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "EZAudio"
s.version = "0.3.0"
s.version = "0.4.0"
s.summary = "A simple, intuitive audio framework for iOS and OSX useful for anyone doing audio processing and/or audio-based visualizations."
s.homepage = "https://github.com/syedhali/EZAudio"
s.screenshots = "https://s3-us-west-1.amazonaws.com/ezaudio-media/EZAudioSummary.png"
@@ -15,4 +15,4 @@ Pod::Spec.new do |s|
s.osx.frameworks = 'AudioToolbox','AudioUnit','CoreAudio','QuartzCore','OpenGL','GLKit'
s.dependency 'TPCircularBuffer', '~> 0.0'
s.requires_arc = true;
end
end
+25 -9
View File
@@ -33,6 +33,14 @@
*/
+ (NSArray *)inputDevices;
//------------------------------------------------------------------------------
/**
Enumerates all the available output devices and returns the result in an NSArray of EZAudioDevice instances.
@return An NSArray of output EZAudioDevice instances.
*/
+ (NSArray *)outputDevices;
#if TARGET_OS_IPHONE
/**
@@ -42,6 +50,13 @@
*/
+ (EZAudioDevice *)currentInputDevice;
/**
Provides the current EZAudioDevice that is being used to output audio.
- iOS only
@return An EZAudioDevice instance representing the currently selected ouotput device.
*/
+ (EZAudioDevice *)currentOutputDevice;
//------------------------------------------------------------------------------
/**
@@ -52,6 +67,16 @@
+ (void)enumerateInputDevicesUsingBlock:(void(^)(EZAudioDevice *device,
BOOL *stop))block;
//------------------------------------------------------------------------------
/**
Enumerates all the available output devices.
- iOS only
@param block When enumerating this block executes repeatedly for each EZAudioDevice found. It contains two arguments - first, the EZAudioDevice found, then a pointer to a stop BOOL to allow breaking out of the enumeration)
*/
+ (void)enumerateOutputDevicesUsingBlock:(void (^)(EZAudioDevice *device,
BOOL *stop))block;
#elif TARGET_OS_MAC
/**
@@ -63,15 +88,6 @@
//------------------------------------------------------------------------------
/**
Enumerates all the available output devices and returns the result in an NSArray of EZAudioDevice instances.
- OSX only
@return An NSArray of output EZAudioDevice instances.
*/
+ (NSArray *)outputDevices;
//------------------------------------------------------------------------------
/**
Enumerates all the available devices.
- OSX only
+61
View File
@@ -49,6 +49,19 @@
//------------------------------------------------------------------------------
+ (EZAudioDevice *)currentOutputDevice
{
AVAudioSession *session = [AVAudioSession sharedInstance];
AVAudioSessionPortDescription *port = [[[session currentRoute] outputs] firstObject];
AVAudioSessionDataSourceDescription *dataSource = [session outputDataSource];
EZAudioDevice *device = [[EZAudioDevice alloc] init];
device.port = port;
device.dataSource = dataSource;
return device;
}
//------------------------------------------------------------------------------
+ (NSArray *)inputDevices
{
__block NSMutableArray *devices = [NSMutableArray array];
@@ -61,6 +74,18 @@
//------------------------------------------------------------------------------
+ (NSArray *)outputDevices
{
__block NSMutableArray *devices = [NSMutableArray array];
[self enumerateOutputDevicesUsingBlock:^(EZAudioDevice *device, BOOL *stop)
{
[devices addObject:device];
}];
return devices;
}
//------------------------------------------------------------------------------
+ (void)enumerateInputDevicesUsingBlock:(void (^)(EZAudioDevice *, BOOL *))block
{
if (!block)
@@ -101,6 +126,42 @@
//------------------------------------------------------------------------------
+ (void)enumerateOutputDevicesUsingBlock:(void (^)(EZAudioDevice *, BOOL *))block
{
if (!block)
{
return;
}
AVAudioSessionRouteDescription *currentRoute = [[AVAudioSession sharedInstance] currentRoute];
NSArray *portDescriptions = [currentRoute outputs];
BOOL stop;
for (AVAudioSessionPortDescription *outputDevicePortDescription in portDescriptions)
{
// add any additional sub-devices
NSArray *dataSources = [outputDevicePortDescription dataSources];
if (dataSources.count)
{
for (AVAudioSessionDataSourceDescription *outputDeviceDataSourceDescription in dataSources)
{
EZAudioDevice *device = [[EZAudioDevice alloc] init];
device.port = outputDevicePortDescription;
device.dataSource = outputDeviceDataSourceDescription;
block(device, &stop);
}
}
else
{
EZAudioDevice *device = [[EZAudioDevice alloc] init];
device.port = outputDevicePortDescription;
block(device, &stop);
}
}
}
//------------------------------------------------------------------------------
- (NSString *)name
{
NSMutableString *name = [NSMutableString string];
+5 -3
View File
@@ -194,12 +194,12 @@
_audioFile = [EZAudioFile audioFileWithURL:audioFile.url];
_audioFile.delegate = self;
NSAssert(_output,@"No output was found, this should by default be the EZOutput shared instance");
[_output setAudioStreamBasicDescription:self.audioFile.clientFormat];
[_output setInputFormat:self.audioFile.clientFormat];
}
-(void)setOutput:(EZOutput*)output {
_output = output;
_output.outputDataSource = self;
_output.dataSource = self;
}
#pragma mark - Methods
@@ -278,9 +278,10 @@ withNumberOfChannels:(UInt32)numberOfChannels {
}
#pragma mark - EZOutputDataSource
-(void) output:(EZOutput *)output
-(OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp
{
if (self.audioFile)
{
@@ -294,6 +295,7 @@ withNumberOfChannels:(UInt32)numberOfChannels {
[self seekToFrame:0];
}
}
return noErr;
}
@end
+11
View File
@@ -46,6 +46,17 @@ typedef struct
TPCircularBuffer circularBuffer;
} EZPlotHistoryInfo;
//------------------------------------------------------------------------------
/**
A data structure that holds information about a node in the context of an AUGraph.
*/
typedef struct
{
AudioUnit audioUnit;
AUNode node;
} EZAudioNodeInfo;
//------------------------------------------------------------------------------
#pragma mark - Types
//------------------------------------------------------------------------------
+5 -4
View File
@@ -36,7 +36,7 @@
//------------------------------------------------------------------------------
/**
The delegate for the EZMicrophone provides a receiver for the incoming audio data events. When the microphone has been successfully internally configured it will try to send its delegate an AudioStreamBasicDescription describing the format of the incoming audio data.
The EZMicrophoneDelegate for the EZMicrophone provides a receiver for the incoming audio data events. When the microphone has been successfully internally configured it will try to send its delegate an AudioStreamBasicDescription describing the format of the incoming audio data.
The audio data itself is sent back to the delegate in various forms:
@@ -55,10 +55,9 @@
///-----------------------------------------------------------
/**
Called anytime the input device changes on an `EZMicrophone` instance. Mac only.
Called anytime the input device changes on an `EZMicrophone` instance.
@param microphone The instance of the EZMicrophone that triggered the event.
@param device The instance of the new EZAudioDevice the microphone is using to pull input.
@param notification Incase the device changed because of a notification (like from AVAudioSession) then we provide that notification to give the full context of the change.
*/
- (void)microphone:(EZMicrophone *)microphone changedDevice:(EZAudioDevice *)device;
@@ -77,7 +76,7 @@
///-----------------------------------------------------------
/**
Returns back a float array of the audio received. This occurs on the background thread so any drawing code must explicity perform its functions on the main thread.
This method provides an array of float arrays of the audio received, each float array representing a channel of audio data This occurs on the background thread so any drawing code must explicity perform its functions on the main thread.
@param microphone The instance of the EZMicrophone that triggered the event.
@param buffer The audio data as an array of float arrays. In a stereo signal buffer[0] represents the left channel while buffer[1] would represent the right channel.
@param bufferSize The size of each of the buffers (the length of each float array).
@@ -304,7 +303,9 @@
*/
- (AudioUnit *)audioUnit;
//------------------------------------------------------------------------------
#pragma mark - Setters
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Customizing The Microphone Stream Format
+5 -3
View File
@@ -535,21 +535,23 @@ static OSStatus EZAudioMicrophoneCallback(void *inRefCon,
- (void)setOutput:(EZOutput *)output
{
_output = output;
[_output setAudioStreamBasicDescription:self.audioStreamBasicDescription];
_output.outputDataSource = self;
_output.inputFormat = self.audioStreamBasicDescription;
_output.dataSource = self;
}
//------------------------------------------------------------------------------
#pragma mark - EZOutputDataSource
//------------------------------------------------------------------------------
- (void) output:(EZOutput *)output
- (OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp
{
memcpy(audioBufferList,
self.info->audioBufferList,
sizeof(AudioBufferList) + (self.info->audioBufferList->mNumberBuffers - 1)*sizeof(AudioBuffer));
return noErr;
}
//------------------------------------------------------------------------------
+249 -74
View File
@@ -30,72 +30,102 @@
#import <AudioUnit/AudioUnit.h>
#endif
#import "TPCircularBuffer.h"
@class EZAudioDevice;
@class EZOutput;
//------------------------------------------------------------------------------
#pragma mark - Constants
//------------------------------------------------------------------------------
FOUNDATION_EXPORT UInt32 const EZOutputMaximumFramesPerSlice;
FOUNDATION_EXPORT Float64 const EZOutputDefaultSampleRate;
//------------------------------------------------------------------------------
#pragma mark - EZOutputDataSource
//------------------------------------------------------------------------------
/**
The EZOutputDataSource (required for the EZOutput) specifies a receiver to provide audio data when the EZOutput is started. Only ONE datasource method is expected to be implemented and priority is given as such:
1.) `output:callbackWithActionFlags:inTimeStamp:inBusNumber:inNumberFrames:ioData:`
2.) `outputShouldUseCircularBuffer:`
3.) `output:needsBufferListWithFrames:withBufferSize:`
The EZOutputDataSource specifies a receiver to provide audio data when the EZOutput is started. Since the 0.4.0 release this has been simplified to only one data source method.
*/
@protocol EZOutputDataSource <NSObject>
@optional
///-----------------------------------------------------------
/// @name Pulling The Audio Data
/// @name Providing Audio Data
///-----------------------------------------------------------
/**
Provides complete override of the output callback function. The delegate is expected to
@param output The instance of the EZOutput that asked for the data
@param ioActionFlags AudioUnitRenderActionFlags provided by the output callback
@param inTimeStamp AudioTimeStamp reference provided by the output callback
@param inBusNumber UInt32 representing the bus number provided by the output callback
@param inNumberFrames UInt32 representing the number of frames provided by the output callback
@param ioData AudioBufferList pointer representing the audio data that will be used for output provided by the output callback (fill this!)
*/
-(void)output:(EZOutput*)output
callbackWithActionFlags:(AudioUnitRenderActionFlags*)ioActionFlags
inTimeStamp:(const AudioTimeStamp*)inTimeStamp
inBusNumber:(UInt32)inBusNumber
inNumberFrames:(UInt32)inNumberFrames
ioData:(AudioBufferList*)ioData;
@required
/**
Provides output using a circular
@param output The instance of the EZOutput that asked for the data
@return The EZOutputDataSource's TPCircularBuffer structure holding the audio data in a circular buffer
*/
-(TPCircularBuffer*)outputShouldUseCircularBuffer:(EZOutput *)output;
/**
Provides a way to provide output with data anytime the EZOutput needs audio data to play. This function provides an already allocated AudioBufferList to use for providing audio data into the output buffer.
Provides a way to provide output with data anytime the EZOutput needs audio data to play. This function provides an already allocated AudioBufferList to use for providing audio data into the output buffer. The expected format of the audio data provided here is specified by the EZOutput `inputFormat` property. This audio data will be converted into the client format specified by the EZOutput `clientFormat` property.
@param output The instance of the EZOutput that asked for the data.
@param audioBufferList The AudioBufferList structure pointer that needs to be filled with audio data
@param frames The amount of frames as a UInt32 that output will need to properly fill its output buffer.
@return A pointer to the AudioBufferList structure holding the audio data. If nil or NULL, will output silence.
@param timestamp A AudioTimeStamp pointer to use if you need the current host time.
@return An OSStatus code. If there was no error then use the noErr status code.
*/
-(void) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList*)audioBufferList
withNumberOfFrames:(UInt32)frames;
- (OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp;
@end
//------------------------------------------------------------------------------
#pragma mark - EZOutputDelegate
//------------------------------------------------------------------------------
/**
The EZOutputDelegate for the EZOutput component provides a receiver to handle play state, device, and audio data change events. This is very similar to the EZMicrophoneDelegate for the EZMicrophone and the EZAudioFileDelegate for the EZAudioFile.
*/
@protocol EZOutputDelegate <NSObject>
@optional
/**
Called anytime the EZOutput starts or stops.
@param output The instance of the EZOutput that triggered the event.
@param isPlaying A BOOL indicating whether the EZOutput instance is playing or not.
*/
- (void)output:(EZOutput *)output changedPlayingState:(BOOL)isPlaying;
//------------------------------------------------------------------------------
/**
Called anytime the `device` changes on an EZOutput instance.
@param output The instance of the EZOutput that triggered the event.
@param device The instance of the new EZAudioDevice the output is using to play audio data.
*/
- (void)output:(EZOutput *)output changedDevice:(EZAudioDevice *)device;
//------------------------------------------------------------------------------
/**
Like the EZMicrophoneDelegate, for the EZOutput this method provides an array of float arrays of the audio received, each float array representing a channel of audio data. This occurs on the background thread so any drawing code must explicity perform its functions on the main thread.
@param output The instance of the EZOutput that triggered the event.
@param buffer The audio data as an array of float arrays. In a stereo signal buffer[0] represents the left channel while buffer[1] would represent the right channel.
@param bufferSize A UInt32 representing the size of each of the buffers (the length of each float array).
@param numberOfChannels A UInt32 representing the number of channels (you can use this to know how many float arrays are in the `buffer` parameter.
@warning This function executes on a background thread to avoid blocking any audio operations. If operations should be performed on any other thread (like the main thread) it should be performed within a dispatch block like so: dispatch_async(dispatch_get_main_queue(), ^{ ...Your Code... })
*/
- (void) output:(EZOutput *)output
playedAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels;
//------------------------------------------------------------------------------
@end
/**
The EZOutput component provides a generic output to glue all the other EZAudio components together and push whatever sound you've created to the default output device (think opposite of the microphone). The EZOutputDataSource provides the required AudioBufferList needed to populate the output buffer.
The EZOutput component provides a generic output to glue all the other EZAudio components together and push whatever sound you've created to the default output device (think opposite of the microphone). The EZOutputDataSource provides the required AudioBufferList needed to populate the output buffer while the EZOutputDelegate provides the same kind of mechanism as the EZMicrophoneDelegate or EZAudioFileDelegate in that you will receive a callback that provides non-interleaved, float data for visualizing the output (done using an internal float converter). As of 0.4.0 the EZOutput has been simplified to a single EZOutputDataSource method and now uses an AUGraph to provide format conversion from the `inputFormat` to the playback graph's `clientFormat` linear PCM formats, mixer controls for setting volume and pan settings, hooks to add in any number of effect audio units (see the `connectOutputOfSourceNode:sourceNodeOutputBus:toDestinationNode:destinationNodeInputBus:inGraph:` subclass method), and hardware device toggling (via EZAudioDevice).
*/
@interface EZOutput : NSObject
#pragma mark - Properties
/**
The EZOutputDataSource that provides the required AudioBufferList to the output callback function
*/
@property (nonatomic,assign) id<EZOutputDataSource>outputDataSource;
//------------------------------------------------------------------------------
#pragma mark - Initializers
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Initializers
///-----------------------------------------------------------
@@ -105,29 +135,38 @@ inNumberFrames:(UInt32)inNumberFrames
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@return A newly created instance of the EZOutput class.
*/
-(id)initWithDataSource:(id<EZOutputDataSource>)dataSource;
- (instancetype)initWithDataSource:(id<EZOutputDataSource>)dataSource;
/**
Creates a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@param audioStreamBasicDescription The AudioStreamBasicDescription of the EZOutput.
@warning AudioStreamBasicDescriptions that are invalid will cause the EZOutput to fail to initialize
@param inputFormat The AudioStreamBasicDescription of the EZOutput.
@warning AudioStreamBasicDescription input formats must be linear PCM!
@return A newly created instance of the EZOutput class.
*/
-(id) initWithDataSource:(id<EZOutputDataSource>)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
- (instancetype)initWithDataSource:(id<EZOutputDataSource>)dataSource
inputFormat:(AudioStreamBasicDescription)inputFormat;
//------------------------------------------------------------------------------
#pragma mark - Class Initializers
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Class Initializers
///-----------------------------------------------------------
/**
Class method to create a new instance of the EZOutput
@return A newly created instance of the EZOutput class.
*/
+ (instancetype)output;
/**
Class method to create a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@param dataSource The EZOutputDataSource that will be used to pull the audio data for the output callback.
@return A newly created instance of the EZOutput class.
*/
+(EZOutput*)outputWithDataSource:(id<EZOutputDataSource>)dataSource;
+ (instancetype)outputWithDataSource:(id<EZOutputDataSource>)dataSource;
/**
Class method to create a new instance of the EZOutput and allows the caller to specify an EZOutputDataSource.
@@ -136,10 +175,13 @@ inNumberFrames:(UInt32)inNumberFrames
@warning AudioStreamBasicDescriptions that are invalid will cause the EZOutput to fail to initialize
@return A newly created instance of the EZOutput class.
*/
+(EZOutput*)outputWithDataSource:(id<EZOutputDataSource>)dataSource
withAudioStreamBasicDescription:(AudioStreamBasicDescription)audioStreamBasicDescription;
+ (instancetype)outputWithDataSource:(id<EZOutputDataSource>)dataSource
inputFormat:(AudioStreamBasicDescription)inputFormat;
//------------------------------------------------------------------------------
#pragma mark - Singleton
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Shared Instance
///-----------------------------------------------------------
@@ -148,9 +190,123 @@ inNumberFrames:(UInt32)inNumberFrames
Creates a shared instance of the EZOutput (one app will usually only need one output and share the role of the EZOutputDataSource).
@return The shared instance of the EZOutput class.
*/
+(EZOutput*)sharedOutput;
+ (instancetype)sharedOutput;
//------------------------------------------------------------------------------
#pragma mark - Properties
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Setting/Getting The Stream Formats
///-----------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure used at the beginning of the playback graph which is then converted into the `clientFormat` using the AUConverter audio unit.
@warning The AudioStreamBasicDescription set here must be linear PCM. Compressed formats are not supported...the EZAudioFile's clientFormat performs the audio conversion on the fly from compressed to linear PCM so there is no additional work to be done there.
@return An AudioStreamBasicDescription structure describing
*/
@property (nonatomic, readwrite) AudioStreamBasicDescription inputFormat;
//------------------------------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure that serves as the common format used throughout the playback graph (similar to how the EZAudioFile as a clientFormat that is linear PCM to be shared amongst other components). The `inputFormat` is converted into this format at the beginning of the playback graph using an AUConverter audio unit. Defaults to the whatever the `defaultClientFormat` method returns is if a custom one isn't explicitly set.
@warning The AudioStreamBasicDescription set here must be linear PCM. Compressed formats are not supported by Audio Units.
@return An AudioStreamBasicDescription structure describing the common client format for the playback graph.
*/
@property (nonatomic, readwrite) AudioStreamBasicDescription clientFormat;
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Setting/Getting The Data Source and Delegate
///-----------------------------------------------------------
/**
The EZOutputDataSource that provides the audio data in the `inputFormat` for the EZOutput to play. If an EZOutputDataSource is not specified then the EZOutput will just output silence.
*/
@property (nonatomic, weak) id<EZOutputDataSource> dataSource;
//------------------------------------------------------------------------------
/**
The EZOutputDelegate for which to handle the output callbacks
*/
@property (nonatomic, weak) id<EZOutputDelegate> delegate;
//------------------------------------------------------------------------------
/**
Provides a flag indicating whether the EZOutput is pulling audio data from the EZOutputDataSource for playback.
@return YES if the EZOutput is running, NO if it is stopped
*/
@property (readonly) BOOL isPlaying;
//------------------------------------------------------------------------------
/**
Provides the current pan from the audio player's mixer audio unit in the playback graph. Setting the pan adjusts the direction of the audio signal from left (0) to right (1). Default is 0.5 (middle).
*/
@property (nonatomic, assign) float pan;
//------------------------------------------------------------------------------
/**
Provides the current volume from the audio player's mixer audio unit in the playback graph. Setting the volume adjusts the gain of the output between 0 and 1. Default is 1.
*/
@property (nonatomic, assign) float volume;
//------------------------------------------------------------------------------
#pragma mark - Core Audio Properties
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Core Audio Properties
///-----------------------------------------------------------
/**
The AUGraph used to chain together the converter, mixer, and output audio units.
*/
@property (readonly) AUGraph graph;
//------------------------------------------------------------------------------
/**
The AudioUnit that is being used to convert the audio data coming into the output's playback graph.
*/
@property (readonly) AudioUnit converterAudioUnit;
//------------------------------------------------------------------------------
/**
The AudioUnit that is being used as the mixer to adjust the volume on the output's playback graph.
*/
@property (readonly) AudioUnit mixerAudioUnit;
//------------------------------------------------------------------------------
/**
The AudioUnit that is being used as the hardware output for the output's playback graph.
*/
@property (readonly) AudioUnit outputAudioUnit;
//------------------------------------------------------------------------------
#pragma mark - Setters
//------------------------------------------------------------------------------
///-----------------------------------------------------------
/// @name Getting/Setting The Output's Hardware Device
///-----------------------------------------------------------
/**
An EZAudioDevice instance that is used to route the audio data out to the speaker. To find a list of available output devices see the EZAudioDevice `outputDevices` method.
*/
@property (nonatomic, strong, readwrite) EZAudioDevice *device;
//------------------------------------------------------------------------------
#pragma mark - Actions
//------------------------------------------------------------------------------
#pragma mark - Events
///-----------------------------------------------------------
/// @name Starting/Stopping The Output
///-----------------------------------------------------------
@@ -158,44 +314,63 @@ inNumberFrames:(UInt32)inNumberFrames
/**
Starts pulling audio data from the EZOutputDataSource to the default device output.
*/
-(void)startPlayback;
- (void)startPlayback;
///-----------------------------------------------------------
/**
Stops pulling audio data from the EZOutputDataSource to the default device output.
*/
-(void)stopPlayback;
- (void)stopPlayback;
//------------------------------------------------------------------------------
#pragma mark - Subclass
//------------------------------------------------------------------------------
#pragma mark - Getters
///-----------------------------------------------------------
/// @name Getting The Output Audio Format
/// @name Subclass
///-----------------------------------------------------------
/**
Provides the AudioStreamBasicDescription structure containing the format of the microphone's audio.
@return An AudioStreamBasicDescription structure describing the format of the microphone's audio.
This method handles connecting the converter node to the mixer node within the AUGraph that is being used as the playback graph. Subclasses can override this method and insert their custom nodes to perform effects processing on the audio data being rendered.
This was inspired by Daniel Kennett's blog post on how to add a custom equalizer to a CocoaLibSpotify SPCoreAudioController's AUGraph. For more information see Daniel's post and example code here: http://ikennd.ac/blog/2012/04/augraph-basics-in-cocoalibspotify/.
@param sourceNode An AUNode representing the node the audio data is coming from.
@param sourceNodeOutputBus A UInt32 representing the output bus from the source node that should be connected into the next node's input bus.
@param destinationNode An AUNode representing the node the audio data should be connected to.
@param destinationNodeInputBus A UInt32 representing the input bus the source node's output bus should be connecting to.
@param graph The AUGraph that is being used to hold the playback graph. Same as from the `graph` property.
@return An OSStatus code. For no error return back `noErr`.
*/
-(AudioStreamBasicDescription)audioStreamBasicDescription;
- (OSStatus)connectOutputOfSourceNode:(AUNode)sourceNode
sourceNodeOutputBus:(UInt32)sourceNodeOutputBus
toDestinationNode:(AUNode)destinationNode
destinationNodeInputBus:(UInt32)destinationNodeInputBus
inGraph:(AUGraph)graph;
///-----------------------------------------------------------
/// @name Getting The State Of The Output
///-----------------------------------------------------------
//------------------------------------------------------------------------------
/**
Provides a flag indicating whether the EZOutput is pulling audio data from the EZOutputDataSource for playback.
@return YES if the EZOutput is pulling audio data to the output device, NO if it is stopped
The default AudioStreamBasicDescription set as the client format of the output if no custom `clientFormat` is set. Defaults to a 44.1 kHz stereo, non-interleaved, float format.
@return An AudioStreamBasicDescription that will be used as the default stream format.
*/
-(BOOL)isPlaying;
- (AudioStreamBasicDescription)defaultClientFormat;
#pragma mark - Setters
///-----------------------------------------------------------
/// @name Customizing The Output Format
///-----------------------------------------------------------
//------------------------------------------------------------------------------
/**
Sets the AudioStreamBasicDescription on the output.
@warning Do not set this during playback.
@param asbd The new AudioStreamBasicDescription to use in place of the current audio format description.
The default AudioStreamBasicDescription set as the `inputFormat` of the output if no custom `inputFormat` is set. Defaults to a 44.1 kHz stereo, non-interleaved, float format.
@return An AudioStreamBasicDescription that will be used as the default stream format.
*/
-(void)setAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd;
- (AudioStreamBasicDescription)defaultInputFormat;
@end
//------------------------------------------------------------------------------
/**
The default value used as the AudioUnit subtype when creating the hardware output component. By default this is kAudioUnitSubType_RemoteIO for iOS and kAudioUnitSubType_HALOutput for OSX.
@warning If you change this to anything other than kAudioUnitSubType_HALOutput for OSX you will get a failed assertion because devices can only be set when using the HAL audio unit.
@return An OSType that represents the AudioUnit subtype for the hardware output component.
*/
- (OSType)outputAudioUnitSubType;
@end
+688 -305
View File
File diff suppressed because it is too large Load Diff
@@ -30,7 +30,7 @@
*/
#import "EZAudio.h"
@interface PassThroughViewController : NSViewController <EZMicrophoneDelegate,EZOutputDataSource>
@interface PassThroughViewController : NSViewController <EZMicrophoneDelegate>
//------------------------------------------------------------------------------
#pragma mark - Components
@@ -36,13 +36,21 @@
/**
Using the EZOutputDataSource to provide output data to the EZOutput component.
*/
@interface PlayFileViewController : NSViewController <NSOpenSavePanelDelegate,EZAudioFileDelegate,EZOutputDataSource>
@interface PlayFileViewController : NSViewController <NSOpenSavePanelDelegate,
EZAudioFileDelegate,
EZOutputDataSource,
EZOutputDelegate>
#pragma mark - Components
/**
The EZAudioFile representing of the currently selected audio file
*/
@property (nonatomic,strong) EZAudioFile *audioFile;
@property (nonatomic, strong) EZAudioFile *audioFile;
/**
The EZOutput component used to output the audio file's audio data.
*/
@property (nonatomic, strong) EZOutput *output;
/**
The CoreGraphics based audio plot
@@ -56,7 +64,7 @@
@property (nonatomic, weak) IBOutlet NSTextField *filePathLabel;
/**
<#Description#>
A label to display the audio file's current position.
*/
@property (nonatomic, weak) IBOutlet NSTextField *positionLabel;
@@ -66,36 +74,36 @@
@property (nonatomic, weak) IBOutlet NSSlider *positionSlider;
/**
<#Description#>
A label to display the value of the rolling history length of the audio plot.
*/
@property (nonatomic, weak) IBOutlet NSTextField *rollingHistoryLengthLabel;
/**
<#Description#>
A slider to adjust the rolling history length of the audio plot.
*/
@property (nonatomic, weak) IBOutlet NSSlider *rollingHistoryLengthSlider;
/**
A slider to adjust the sample rate.
A slider to adjust the volume.
*/
@property (nonatomic, weak) IBOutlet NSSlider *sampleRateSlider;
@property (nonatomic, weak) IBOutlet NSSlider *volumeSlider;
/**
A slider to adjust the sample rate.
A label to display the volume of the audio plot.
*/
@property (nonatomic, weak) IBOutlet NSTextField *sampleRateLabel;
@property (nonatomic, weak) IBOutlet NSTextField *volumeLabel;
/**
A BOOL indicating whether or not we've reached the end of the file
*/
@property (nonatomic,assign) BOOL eof;
#pragma mark - Actions
/**
Changes the sampling frequency on the output unit
The microphone pop up button (contains the menu for choosing a microphone input)
*/
-(IBAction)changeOutputSamplingFrequency:(id)sender;
@property (nonatomic, weak) IBOutlet NSPopUpButton *outputDevicePopUpButton;
#pragma mark - Actions
/**
Switches the plot drawing type between a buffer plot (visualizes the current stream of audio data from the update function) or a rolling plot (visualizes the audio data over time, this is the classic waveform look)
*/
@@ -106,6 +114,11 @@
*/
- (IBAction)changeRollingHistoryLength:(id)sender;
/**
Changes the volume of the audio coming out of the EZOutput.
*/
- (IBAction)changeVolume:(id)sender;
/**
Prompts the file manager and loads in a new audio file into the EZAudioFile representation.
*/
@@ -52,11 +52,24 @@
// Mirror
self.audioPlot.shouldMirror = YES;
//
// Create EZOutput to play audio data
//
self.output = [EZOutput outputWithDataSource:self];
self.output.delegate = self;
//
// Reload the menu for the output device selector popup button
//
[self reloadOutputDevicePopUpButtonMenu];
//
// Configure UI components
//
self.rollingHistoryLengthSlider.intValue = self.audioPlot.rollingHistoryLength;
self.rollingHistoryLengthLabel.intValue = self.audioPlot.rollingHistoryLength;
self.volumeSlider.floatValue = [self.output volume];
self.volumeLabel.floatValue = [self.output volume];
self.rollingHistoryLengthSlider.intValue = [self.audioPlot rollingHistoryLength];
self.rollingHistoryLengthLabel.intValue = [self.audioPlot rollingHistoryLength];
//
// Try opening the sample file
@@ -68,6 +81,14 @@
#pragma mark - Actions
//------------------------------------------------------------------------------
- (void)changedOutput:(NSMenuItem *)item
{
EZAudioDevice *device = [item representedObject];
[self.output setDevice:device];
}
//------------------------------------------------------------------------------
- (void)changePlotType:(id)sender
{
NSInteger selectedSegment = [sender selectedSegment];
@@ -86,13 +107,11 @@
//------------------------------------------------------------------------------
- (void)changeOutputSamplingFrequency:(id)sender
- (void)changeVolume:(id)sender
{
float sampleRate = ((NSSlider *)sender).floatValue;
AudioStreamBasicDescription asbd = [[EZOutput sharedOutput] audioStreamBasicDescription];
asbd.mSampleRate = sampleRate;
[[EZOutput sharedOutput] setAudioStreamBasicDescription:asbd];
self.sampleRateLabel.floatValue = sampleRate;
float value = [(NSSlider *)sender floatValue];
[self.output setVolume:value];
self.volumeLabel.floatValue = value;
}
//------------------------------------------------------------------------------
@@ -123,7 +142,7 @@
-(void)play:(id)sender
{
if (![[EZOutput sharedOutput] isPlaying])
if (![self.output isPlaying])
{
if (self.eof)
{
@@ -133,13 +152,11 @@
{
self.audioPlot.plotType = EZPlotTypeRolling;
}
[EZOutput sharedOutput].outputDataSource = self;
[[EZOutput sharedOutput] startPlayback];
[self.output startPlayback];
}
else
{
[EZOutput sharedOutput].outputDataSource = nil;
[[EZOutput sharedOutput] stopPlayback];
[self.output stopPlayback];
}
}
@@ -191,12 +208,12 @@
//
// Stop playback
//
[[EZOutput sharedOutput] stopPlayback];
[self.output stopPlayback];
//
// Clear the audio plot
//
// [self.audioPlot clear];
[self.audioPlot clear];
//
// Load the audio file and customize the UI
@@ -212,10 +229,7 @@
//
// Set the client format from the EZAudioFile on the output
//
Float64 sampleRate = self.audioFile.clientFormat.mSampleRate;
self.sampleRateSlider.floatValue = sampleRate;
self.sampleRateLabel.floatValue = sampleRate;
[[EZOutput sharedOutput] setAudioStreamBasicDescription:self.audioFile.clientFormat];
[self.output setInputFormat:self.audioFile.clientFormat];
//
// Change back to a buffer plot, but mirror and fill the waveform
@@ -238,29 +252,48 @@
}];
}
//------------------------------------------------------------------------------
#pragma mark - EZAudioFileDelegate
//------------------------------------------------------------------------------
-(void) audioFile:(EZAudioFile *)audioFile
readAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
- (void)reloadOutputDevicePopUpButtonMenu
{
if ([[EZOutput sharedOutput] isPlaying])
NSArray *outputDevices = [EZAudioDevice outputDevices];
NSMenu *menu = [[NSMenu alloc] init];
NSMenuItem *defaultOutputDeviceItem;
for (EZAudioDevice *device in outputDevices)
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
});
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:device.name
action:@selector(changedOutput:)
keyEquivalent:@""];
item.representedObject = device;
item.target = self;
[menu addItem:item];
// If this device is the same one the microphone is using then
// we will use this menu item as the currently selected item
// in the microphone input popup button's list of items. For instance,
// if you are connected to an external display by default the external
// display's microphone might be used instead of the mac's built in
// mic.
if ([device isEqual:[self.output device]])
{
defaultOutputDeviceItem = item;
}
}
self.outputDevicePopUpButton.menu = menu;
//
// Set the selected device to the current selection on the
// microphone input popup button
//
[self.outputDevicePopUpButton selectItem:defaultOutputDeviceItem];
}
//------------------------------------------------------------------------------
#pragma mark - EZAudioFileDelegate
//------------------------------------------------------------------------------
-(void)audioFile:(EZAudioFile *)audioFile
updatedPosition:(SInt64)framePosition {
-(void)audioFile:(EZAudioFile *)audioFile updatedPosition:(SInt64)framePosition
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (![weakSelf.positionSlider.cell isHighlighted])
@@ -275,9 +308,10 @@
#pragma mark - EZOutputDataSource
//------------------------------------------------------------------------------
-(void) output:(EZOutput *)output
-(OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp
{
if (self.audioFile)
{
@@ -291,6 +325,23 @@
[self seekToFrame:0];
}
}
return noErr;
}
//------------------------------------------------------------------------------
#pragma mark - EZOutputDelegate
//------------------------------------------------------------------------------
- (void) output:(EZOutput *)output
playedAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
});
}
//------------------------------------------------------------------------------
@@ -9,15 +9,16 @@
<connections>
<outlet property="audioPlot" destination="Lz1-Gs-1lD" id="V5w-yH-ZVR"/>
<outlet property="filePathLabel" destination="0eT-7c-7fJ" id="IGv-mA-5Hw"/>
<outlet property="outputDevicePopUpButton" destination="0LV-Bi-dGz" id="QTQ-qq-Ro8"/>
<outlet property="playButton" destination="OQp-Lr-dlS" id="K5R-Qg-7DY"/>
<outlet property="plotSegmentControl" destination="bZW-tA-C61" id="4ic-Ou-qh2"/>
<outlet property="positionLabel" destination="KYm-Io-VNv" id="Fhs-Ya-szS"/>
<outlet property="positionSlider" destination="CFP-v0-TzQ" id="EGD-qT-48R"/>
<outlet property="rollingHistoryLengthLabel" destination="vKe-ey-hXI" id="UiN-5S-TOn"/>
<outlet property="rollingHistoryLengthSlider" destination="vj5-qT-JkR" id="sEj-iE-yTV"/>
<outlet property="sampleRateLabel" destination="3ul-3w-l3S" id="5CA-Au-tFa"/>
<outlet property="sampleRateSlider" destination="rRH-oS-VV3" id="8ij-Ff-CZK"/>
<outlet property="view" destination="Xpo-HP-Ost" id="zlj-bW-4iz"/>
<outlet property="volumeLabel" destination="3ul-3w-l3S" id="sXM-mC-tN0"/>
<outlet property="volumeSlider" destination="rRH-oS-VV3" id="kql-X5-amB"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
@@ -27,7 +28,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Lz1-Gs-1lD" customClass="EZAudioPlot">
<rect key="frame" x="0.0" y="0.0" width="480" height="210"/>
<rect key="frame" x="0.0" y="0.0" width="480" height="146"/>
</customView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2Ma-jj-U3z">
<rect key="frame" x="12" y="320" width="125" height="32"/>
@@ -74,22 +75,22 @@
</connections>
</segmentedControl>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CFP-v0-TzQ">
<rect key="frame" x="117" y="242" width="330" height="20"/>
<rect key="frame" x="117" y="242" width="269" height="20"/>
<sliderCell key="cell" continuous="YES" alignment="left" maxValue="100" doubleValue="9.3380614657210401" tickMarkPosition="above" sliderType="linear" id="gPc-pN-dmP"/>
<connections>
<action selector="seekToFrame:" target="-2" id="iVY-so-6X2"/>
</connections>
</slider>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vj5-qT-JkR">
<rect key="frame" x="117" y="217" width="330" height="20"/>
<rect key="frame" x="117" y="217" width="269" height="20"/>
<sliderCell key="cell" continuous="YES" alignment="left" minValue="128" maxValue="1024" doubleValue="128" tickMarkPosition="above" sliderType="linear" id="uRZ-Kf-cgJ"/>
<connections>
<action selector="changeRollingHistoryLength:" target="-2" id="eYD-H1-n52"/>
</connections>
</slider>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7AB-VA-xL3">
<rect key="frame" x="16" y="269" width="85" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Sample Rate:" id="GAa-Hp-OlV">
<rect key="frame" x="16" y="269" width="53" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Volume:" id="GAa-Hp-OlV">
<font key="font" metaFont="systemBold" size="12"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
@@ -112,9 +113,12 @@
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3ul-3w-l3S">
<rect key="frame" x="452" y="269" width="12" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="0" id="vlK-Hb-Yca">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="0" maximumIntegerDigits="42" id="bBU-vS-tEB">
<rect key="frame" x="390" y="269" width="72" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="eyi-2x-AqF"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="0.00" id="vlK-Hb-Yca">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="1" maximumIntegerDigits="1" minimumFractionDigits="2" maximumFractionDigits="2" id="bBU-vS-tEB">
<metadata>
<real key="inspectorSampleValue" value="44"/>
</metadata>
@@ -125,16 +129,19 @@
</textFieldCell>
</textField>
<slider verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rRH-oS-VV3">
<rect key="frame" x="117" y="267" width="330" height="20"/>
<sliderCell key="cell" state="on" alignment="left" minValue="8000" maxValue="88200" doubleValue="44100" tickMarkPosition="above" sliderType="linear" id="xbX-Ce-da5"/>
<rect key="frame" x="117" y="267" width="269" height="20"/>
<sliderCell key="cell" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="0.5" tickMarkPosition="above" sliderType="linear" id="xbX-Ce-da5"/>
<connections>
<action selector="changeOutputSamplingFrequency:" target="-2" id="yWM-Ei-ztA"/>
<action selector="changeVolume:" target="-2" id="iKx-7d-34D"/>
</connections>
</slider>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KYm-Io-VNv">
<rect key="frame" x="452" y="244" width="12" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="0" id="gfS-wb-pFu">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="0" maximumIntegerDigits="42" id="py5-BY-fQN">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vKe-ey-hXI">
<rect key="frame" x="390" y="219" width="72" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="7dV-vH-IBh"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="0" id="JiA-3H-vb2">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="0" maximumIntegerDigits="42" id="AYM-Tu-k5w">
<metadata>
<real key="inspectorSampleValue" value="44"/>
</metadata>
@@ -144,10 +151,38 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vKe-ey-hXI">
<rect key="frame" x="451" y="219" width="12" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="0" id="JiA-3H-vb2">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="0" maximumIntegerDigits="42" id="AYM-Tu-k5w">
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0LV-Bi-dGz" userLabel="microphoneInputPopUpButton">
<rect key="frame" x="16" y="161" width="180" height="26"/>
<constraints>
<constraint firstAttribute="width" constant="175" id="fDF-j7-LMD"/>
</constraints>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="a7m-V2-Mw8" id="VLU-oW-zia">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="uLv-18-vra">
<items>
<menuItem title="Item 1" state="on" id="a7m-V2-Mw8"/>
<menuItem title="Item 2" id="qJe-zH-SrZ"/>
<menuItem title="Item 3" id="zlE-dQ-R4x"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="RRH-G6-xkQ">
<rect key="frame" x="16" y="194" width="50" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Output:" id="2OQ-1o-1vp">
<font key="font" metaFont="systemBold" size="12"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KYm-Io-VNv">
<rect key="frame" x="390" y="244" width="72" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="68" id="fOV-38-VqQ"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="0" id="gfS-wb-pFu">
<numberFormatter key="formatter" formatterBehavior="custom10_4" minimumIntegerDigits="0" maximumIntegerDigits="42" id="py5-BY-fQN">
<metadata>
<real key="inspectorSampleValue" value="44"/>
</metadata>
@@ -159,43 +194,44 @@
</textField>
</subviews>
<constraints>
<constraint firstItem="CFP-v0-TzQ" firstAttribute="baseline" secondItem="Fw5-pm-4w0" secondAttribute="baseline" id="5Iy-Vv-CQo"/>
<constraint firstItem="vKe-ey-hXI" firstAttribute="leading" secondItem="vj5-qT-JkR" secondAttribute="trailing" constant="8" symbolic="YES" id="7ZR-wn-RFM"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="trailing" secondItem="CFP-v0-TzQ" secondAttribute="trailing" id="7rr-13-nCn"/>
<constraint firstItem="vKe-ey-hXI" firstAttribute="baseline" secondItem="vj5-qT-JkR" secondAttribute="baseline" id="9n9-7Q-Uc5"/>
<constraint firstItem="vKe-ey-hXI" firstAttribute="baseline" secondItem="vj5-qT-JkR" secondAttribute="baseline" id="03u-fe-Q2r"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="leading" secondItem="Aa9-nc-WHJ" secondAttribute="trailing" constant="9" id="0QT-jZ-rPL"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="baseline" secondItem="7AB-VA-xL3" secondAttribute="baseline" id="4WU-L2-5TI"/>
<constraint firstItem="3ul-3w-l3S" firstAttribute="trailing" secondItem="bZW-tA-C61" secondAttribute="trailing" constant="-2" id="75o-B9-UmY"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="baseline" secondItem="Aa9-nc-WHJ" secondAttribute="baseline" id="8ia-fE-3Ej"/>
<constraint firstAttribute="bottom" secondItem="Lz1-Gs-1lD" secondAttribute="bottom" id="Cdp-xg-Udu"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="baseline" secondItem="3ul-3w-l3S" secondAttribute="baseline" id="E1v-Nu-5O1"/>
<constraint firstItem="0eT-7c-7fJ" firstAttribute="leading" secondItem="2Ma-jj-U3z" secondAttribute="trailing" constant="11" id="F4y-lz-2p6"/>
<constraint firstItem="7AB-VA-xL3" firstAttribute="top" secondItem="OQp-Lr-dlS" secondAttribute="bottom" constant="9" id="GbY-7Z-81V"/>
<constraint firstItem="Lz1-Gs-1lD" firstAttribute="leading" secondItem="Xpo-HP-Ost" secondAttribute="leading" id="HW1-t3-mGg"/>
<constraint firstItem="OQp-Lr-dlS" firstAttribute="leading" secondItem="2Ma-jj-U3z" secondAttribute="leading" id="Ira-0b-xzU"/>
<constraint firstItem="7AB-VA-xL3" firstAttribute="baseline" secondItem="rRH-oS-VV3" secondAttribute="baseline" id="LQV-fR-ji0"/>
<constraint firstItem="CFP-v0-TzQ" firstAttribute="leading" secondItem="vj5-qT-JkR" secondAttribute="leading" id="May-qJ-5nB"/>
<constraint firstItem="3ul-3w-l3S" firstAttribute="trailing" secondItem="bZW-tA-C61" secondAttribute="trailing" id="Opz-An-TkJ"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="baseline" secondItem="3ul-3w-l3S" secondAttribute="baseline" id="KOD-cZ-e52"/>
<constraint firstItem="CFP-v0-TzQ" firstAttribute="baseline" secondItem="Fw5-pm-4w0" secondAttribute="baseline" id="PbC-KG-EzE"/>
<constraint firstItem="2Ma-jj-U3z" firstAttribute="leading" secondItem="Xpo-HP-Ost" secondAttribute="leading" constant="18" id="PiQ-KC-eta"/>
<constraint firstItem="Fw5-pm-4w0" firstAttribute="top" secondItem="7AB-VA-xL3" secondAttribute="bottom" constant="9" id="SPP-F6-chs"/>
<constraint firstItem="KYm-Io-VNv" firstAttribute="baseline" secondItem="CFP-v0-TzQ" secondAttribute="baseline" id="agk-Cm-yAm"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="trailing" secondItem="CFP-v0-TzQ" secondAttribute="trailing" id="URd-7z-JBO"/>
<constraint firstItem="RRH-G6-xkQ" firstAttribute="leading" secondItem="Xpo-HP-Ost" secondAttribute="leading" constant="18" id="WiW-CU-B7N"/>
<constraint firstAttribute="trailing" secondItem="Lz1-Gs-1lD" secondAttribute="trailing" id="ay9-Mt-iFx"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="baseline" secondItem="Aa9-nc-WHJ" secondAttribute="baseline" id="cBS-XB-jof"/>
<constraint firstAttribute="trailing" secondItem="KYm-Io-VNv" secondAttribute="trailing" constant="18" id="cRX-mp-xiq"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="leading" secondItem="CFP-v0-TzQ" secondAttribute="leading" id="cWn-4f-E04"/>
<constraint firstItem="Fw5-pm-4w0" firstAttribute="leading" secondItem="Aa9-nc-WHJ" secondAttribute="leading" id="cnU-xS-2CO"/>
<constraint firstItem="KYm-Io-VNv" firstAttribute="leading" secondItem="3ul-3w-l3S" secondAttribute="leading" id="dac-nA-d4U"/>
<constraint firstItem="0LV-Bi-dGz" firstAttribute="top" secondItem="RRH-G6-xkQ" secondAttribute="bottom" constant="9" id="dnZ-Rx-iiV"/>
<constraint firstItem="Aa9-nc-WHJ" firstAttribute="top" secondItem="Fw5-pm-4w0" secondAttribute="bottom" constant="9" id="fc6-dV-Lxf"/>
<constraint firstItem="vKe-ey-hXI" firstAttribute="leading" secondItem="vj5-qT-JkR" secondAttribute="trailing" constant="8" symbolic="YES" id="fuB-es-weU"/>
<constraint firstItem="2Ma-jj-U3z" firstAttribute="top" secondItem="Xpo-HP-Ost" secondAttribute="top" constant="18" id="hDY-vI-eWO"/>
<constraint firstItem="OQp-Lr-dlS" firstAttribute="trailing" secondItem="2Ma-jj-U3z" secondAttribute="trailing" id="hXB-Gp-9wN"/>
<constraint firstAttribute="trailing" secondItem="bZW-tA-C61" secondAttribute="trailing" constant="18" id="iUL-br-ASL"/>
<constraint firstAttribute="trailing" secondItem="vKe-ey-hXI" secondAttribute="trailing" constant="19" id="kgc-wp-ndy"/>
<constraint firstItem="OQp-Lr-dlS" firstAttribute="top" secondItem="bZW-tA-C61" secondAttribute="top" id="kny-zR-hiF"/>
<constraint firstItem="Lz1-Gs-1lD" firstAttribute="top" secondItem="Aa9-nc-WHJ" secondAttribute="bottom" constant="9" id="oZE-Hx-FR4"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="trailing" secondItem="CFP-v0-TzQ" secondAttribute="trailing" id="oa1-ct-9bT"/>
<constraint firstItem="Lz1-Gs-1lD" firstAttribute="top" secondItem="0LV-Bi-dGz" secondAttribute="bottom" constant="18" id="l6M-H0-bYA"/>
<constraint firstItem="7AB-VA-xL3" firstAttribute="leading" secondItem="OQp-Lr-dlS" secondAttribute="leading" id="omq-Zw-Gvk"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="leading" secondItem="Aa9-nc-WHJ" secondAttribute="trailing" constant="9" id="qa7-m8-7wP"/>
<constraint firstAttribute="trailing" secondItem="3ul-3w-l3S" secondAttribute="trailing" constant="18" id="rtO-ix-cUt"/>
<constraint firstItem="KYm-Io-VNv" firstAttribute="baseline" secondItem="CFP-v0-TzQ" secondAttribute="baseline" id="q8e-0e-Xqt"/>
<constraint firstItem="0eT-7c-7fJ" firstAttribute="top" secondItem="2Ma-jj-U3z" secondAttribute="top" id="snu-Ma-cHX"/>
<constraint firstItem="3ul-3w-l3S" firstAttribute="leading" secondItem="KYm-Io-VNv" secondAttribute="leading" id="tKc-D3-J6f"/>
<constraint firstItem="OQp-Lr-dlS" firstAttribute="top" secondItem="2Ma-jj-U3z" secondAttribute="bottom" constant="12" symbolic="YES" id="tkR-bR-msf"/>
<constraint firstItem="3ul-3w-l3S" firstAttribute="leading" secondItem="rRH-oS-VV3" secondAttribute="trailing" constant="9" id="udS-FO-wJL"/>
<constraint firstItem="0LV-Bi-dGz" firstAttribute="leading" secondItem="Xpo-HP-Ost" secondAttribute="leading" constant="18" id="tmm-8d-ldM"/>
<constraint firstItem="3ul-3w-l3S" firstAttribute="leading" secondItem="rRH-oS-VV3" secondAttribute="trailing" constant="8" id="uF6-oM-5lN"/>
<constraint firstItem="Fw5-pm-4w0" firstAttribute="leading" secondItem="7AB-VA-xL3" secondAttribute="leading" id="vNA-c3-Gcy"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="leading" secondItem="CFP-v0-TzQ" secondAttribute="leading" id="yJz-Qg-823"/>
<constraint firstItem="RRH-G6-xkQ" firstAttribute="top" secondItem="Aa9-nc-WHJ" secondAttribute="bottom" constant="9" id="w92-Np-SYg"/>
<constraint firstItem="rRH-oS-VV3" firstAttribute="trailing" secondItem="CFP-v0-TzQ" secondAttribute="trailing" id="wdS-Vt-caT"/>
<constraint firstItem="vj5-qT-JkR" firstAttribute="leading" secondItem="CFP-v0-TzQ" secondAttribute="leading" id="wek-S9-BzW"/>
</constraints>
<point key="canvasLocation" x="191" y="409"/>
</customView>
@@ -14,20 +14,7 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Remember to configure your audio session
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = NULL;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];
if( err ){
NSLog(@"There was an error creating the audio session");
}
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:NULL];
if( err ){
NSLog(@"There was an error sending the audio to the speakers");
}
// Override point for customization after application launch.
return YES;
}
@@ -21,10 +21,30 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pcc-nf-p5k">
<rect key="frame" x="0.0" y="435" width="600" height="165"/>
<rect key="frame" x="0.0" y="396" width="600" height="204"/>
<subviews>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="d3R-ct-df2">
<rect key="frame" x="118" y="9" width="467" height="31"/>
<color key="tintColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<action selector="changeVolume:" destination="scx-fQ-Cxi" eventType="valueChanged" id="zBC-Ej-fju"/>
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Volume:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iS5-xf-09a">
<rect key="frame" x="18" y="15" width="49" height="16"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/>
<color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.70000000000000007" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="165" id="CMG-37-Ji8"/>
<constraint firstAttribute="height" constant="204" id="CMG-37-Ji8"/>
<constraint firstItem="iS5-xf-09a" firstAttribute="leading" secondItem="Pcc-nf-p5k" secondAttribute="leading" constant="18" id="MWr-Og-OGn"/>
<constraint firstItem="d3R-ct-df2" firstAttribute="top" secondItem="Pcc-nf-p5k" secondAttribute="top" constant="9" id="Ukk-HX-GtW"/>
<constraint firstItem="d3R-ct-df2" firstAttribute="leading" secondItem="iS5-xf-09a" secondAttribute="trailing" constant="53" id="cE7-h4-F6T"/>
<constraint firstItem="iS5-xf-09a" firstAttribute="top" secondItem="Pcc-nf-p5k" secondAttribute="top" constant="15" id="cFA-qs-q09"/>
<constraint firstAttribute="trailing" secondItem="d3R-ct-df2" secondAttribute="trailing" constant="17" id="rCY-Vg-KOz"/>
</constraints>
</view>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="X0b-lY-wCz">
@@ -130,7 +150,9 @@
<outlet property="audioPlot" destination="kt3-hw-eFY" id="9mm-d1-vJk"/>
<outlet property="filePathLabel" destination="i5r-ex-ukW" id="GRl-ld-nWi"/>
<outlet property="framePositionSlider" destination="Oc2-kU-kAJ" id="z0M-Q9-JAb"/>
<outlet property="rollingHistorySlider" destination="2qJ-Va-Qht" id="yf8-JW-5yM"/>
<outlet property="view" destination="PED-9r-Xub" id="Xxb-En-D2X"/>
<outlet property="volumeSlider" destination="d3R-ct-df2" id="pAW-BF-AFa"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="g7v-Xp-r3F" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -20,29 +20,45 @@
Using the EZOutputDataSource to provide output data to the EZOutput component.
*/
@interface PlayFileViewController : UIViewController <EZAudioFileDelegate,
EZOutputDataSource>
EZOutputDataSource,
EZOutputDelegate>
#pragma mark - Components
/**
The EZAudioFile representing of the currently selected audio file
*/
@property (nonatomic,strong) EZAudioFile *audioFile;
@property (nonatomic, strong) EZAudioFile *audioFile;
/**
The EZOutput representing the output currently being used to play the audio file.
*/
@property (nonatomic, strong) EZOutput *output;
/**
The CoreGraphics based audio plot
*/
@property (nonatomic,weak) IBOutlet EZAudioPlot *audioPlot;
@property (nonatomic, weak) IBOutlet EZAudioPlot *audioPlot;
#pragma mark - UI Extras
/**
A label to display the current file path with the waveform shown
*/
@property (nonatomic,weak) IBOutlet UILabel *filePathLabel;
@property (nonatomic, weak) IBOutlet UILabel *filePathLabel;
/**
A slider to indicate the current frame position in the audio file
*/
@property (nonatomic,weak) IBOutlet UISlider *framePositionSlider;
@property (nonatomic, weak) IBOutlet UISlider *framePositionSlider;
/**
A slider to indicate the current rolling history length of the audio plot.
*/
@property (nonatomic, weak) IBOutlet UISlider *rollingHistorySlider;
/**
A slider to indicate the volume on the audio player
*/
@property (nonatomic, weak) IBOutlet UISlider *volumeSlider;
/**
A BOOL indicating whether or not we've reached the end of the file
@@ -60,6 +76,11 @@
*/
- (IBAction)changeRollingHistoryLength:(id)sender;
/**
Changes the volume of the audio player.
*/
- (IBAction)changeVolume:(id)sender;
/**
Begins playback if a file is loaded. Pauses if the file is already playing.
*/
@@ -19,27 +19,55 @@
#pragma mark - Customize the Audio Plot
- (void)viewDidLoad
{
[super viewDidLoad];
/*
Customizing the audio plot's look
*/
// Background color
self.audioPlot.backgroundColor = [UIColor colorWithRed: 0.816 green: 0.349 blue: 0.255 alpha: 1];
// Waveform color
self.audioPlot.color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
// Plot type
self.audioPlot.plotType = EZPlotTypeBuffer;
// Fill
self.audioPlot.shouldFill = YES;
// Mirror
self.audioPlot.shouldMirror = YES;
/*
Try opening the sample file
*/
[self openFileWithFilePathURL:[NSURL fileURLWithPath:kAudioFileDefault]];
[super viewDidLoad];
//
// Setup the AVAudioSession. EZMicrophone will not work properly on iOS
// if you don't do this!
//
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error)
{
NSLog(@"Error setting up audio session category: %@", error.localizedDescription);
}
[session setActive:YES error:&error];
if (error)
{
NSLog(@"Error setting up audio session active: %@", error.localizedDescription);
}
//
// Customize the plot's look
//
// Background color
self.audioPlot.backgroundColor = [UIColor colorWithRed: 0.816 green: 0.349 blue: 0.255 alpha: 1];
// Waveform color
self.audioPlot.color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
// Plot type
self.audioPlot.plotType = EZPlotTypeBuffer;
// Fill
self.audioPlot.shouldFill = YES;
// Mirror
self.audioPlot.shouldMirror = YES;
//
// Create an EZOutput instance
//
self.output = [EZOutput outputWithDataSource:self];
self.output.delegate = self;
//
// Customize UI controls
//
self.volumeSlider.value = [self.output volume];
self.rollingHistorySlider.value = [self.audioPlot rollingHistoryLength];
//
// Try opening the sample file
//
[self openFileWithFilePathURL:[NSURL fileURLWithPath:kAudioFileDefault]];
}
//------------------------------------------------------------------------------
@@ -72,18 +100,26 @@
//------------------------------------------------------------------------------
- (void)changeVolume:(id)sender
{
float value = [(UISlider *)sender value];
[self.output setVolume:value];
}
//------------------------------------------------------------------------------
- (void)openFileWithFilePathURL:(NSURL *)filePathURL
{
// Stop playback
[[EZOutput sharedOutput] stopPlayback];
[self.output stopPlayback];
self.audioFile = [EZAudioFile audioFileWithURL:filePathURL delegate:self];
self.eof = NO;
self.filePathLabel.text = filePathURL.lastPathComponent;
self.framePositionSlider.maximumValue = (float)self.audioFile.totalFrames;
// Set the client format from the EZAudioFile on the output
[[EZOutput sharedOutput] setAudioStreamBasicDescription:self.audioFile.clientFormat];
// Set the input format from the EZAudioFile on the output
[self.output setInputFormat:[self.audioFile clientFormat]];
// Plot the whole waveform
self.audioPlot.plotType = EZPlotTypeBuffer;
@@ -93,29 +129,27 @@
__weak typeof (self) weakSelf = self;
[self.audioFile getWaveformDataWithCompletionBlock:^(float **waveformData,
int length)
{
[weakSelf.audioPlot updateBuffer:waveformData[0]
withBufferSize:length];
}];
{
[weakSelf.audioPlot updateBuffer:waveformData[0]
withBufferSize:length];
}];
}
//------------------------------------------------------------------------------
- (void)play:(id)sender
{
if (![[EZOutput sharedOutput] isPlaying])
if (![self.output isPlaying])
{
if (self.eof)
{
[self.audioFile seekToFrame:0];
}
[EZOutput sharedOutput].outputDataSource = self;
[[EZOutput sharedOutput] startPlayback];
[self.output startPlayback];
}
else
{
[EZOutput sharedOutput].outputDataSource = nil;
[[EZOutput sharedOutput] stopPlayback];
[self.output stopPlayback];
}
}
@@ -156,30 +190,6 @@
#pragma mark - EZAudioFileDelegate
//------------------------------------------------------------------------------
- (void) audioFile:(EZAudioFile *)audioFile
readAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if ([EZOutput sharedOutput].isPlaying)
{
if (weakSelf.audioPlot.plotType == EZPlotTypeBuffer &&
weakSelf.audioPlot.shouldFill == YES &&
weakSelf.audioPlot.shouldMirror == YES)
{
weakSelf.audioPlot.shouldFill = NO;
weakSelf.audioPlot.shouldMirror = NO;
}
[weakSelf.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
}
});
}
//------------------------------------------------------------------------------
- (void)audioFile:(EZAudioFile *)audioFile
updatedPosition:(SInt64)framePosition
{
@@ -196,29 +206,51 @@
#pragma mark - EZOutputDataSource
//------------------------------------------------------------------------------
- (void) output:(EZOutput *)output
- (OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp
{
if ( self.audioFile )
if (self.audioFile)
{
UInt32 bufferSize;
BOOL eof;
[self.audioFile readFrames:frames
audioBufferList:audioBufferList
bufferSize:&bufferSize
eof:&_eof];
if ( _eof )
eof:&eof];
if (eof)
{
[self seekToFrame:0];
[self.audioFile seekToFrame:0];
}
}
return noErr;
}
//------------------------------------------------------------------------------
#pragma mark - EZOutputDelegate
//------------------------------------------------------------------------------
- (AudioStreamBasicDescription)outputHasAudioStreamBasicDescription:(EZOutput *)output
- (void) output:(EZOutput *)output
playedAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
return self.audioFile.clientFormat;
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.output isPlaying])
{
if (weakSelf.audioPlot.plotType == EZPlotTypeBuffer &&
weakSelf.audioPlot.shouldFill == YES &&
weakSelf.audioPlot.shouldMirror == YES)
{
weakSelf.audioPlot.shouldFill = NO;
weakSelf.audioPlot.shouldMirror = NO;
}
[weakSelf.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
}
});
}
//------------------------------------------------------------------------------
+1 -12
View File
@@ -3,9 +3,6 @@
#EZAudio
A simple, intuitive audio framework for iOS and OSX.
*The Official EZAudio Page:*
http://syedharisali.com/projects/EZAudio/getting-started
##Features
![alt text](https://s3-us-west-1.amazonaws.com/ezaudio-media/EZAudioSummary.png "EZAudioFeatures")
@@ -82,9 +79,6 @@ The official documentation for EZAudio can be found here: http://cocoadocs.org/d
<br>You can also generate the docset yourself using appledocs by running the appledocs on the EZAudio source folder.
##Getting Started
*To see the full project page, interactive Getting Started guide, and Documentation go here:*
http://syedharisali.com/projects/EZAudio/getting-started
To begin using `EZAudio` you must first make sure you have the proper build requirements and frameworks. Below you'll find explanations of each component and code snippets to show how to use each to perform common tasks like getting microphone data, updating audio waveform plots, reading/seeking through audio files, and performing playback.
###Build Requirements
@@ -114,14 +108,11 @@ To begin using `EZAudio` you must first make sure you have the proper build requ
You can add EZAudio to your project in a few ways: <br><br>1.) The easiest way to use EZAudio is via <a href="http://cocoapods.org/", target="_blank">Cocoapods</a>. Simply add EZAudio to your <a href="http://guides.cocoapods.org/using/the-podfile.html", target="_blank">Podfile</a> like so:
`
pod 'EZAudio', '~> 0.1.0'
pod 'EZAudio', '~> 0.4.0'
`
2.) Alternatively, you could clone or fork this repo and just drag and drop the source into your project.
*For more information see main project page:*
http://syedharisali.com/projects/EZAudio/getting-started
##Core Components
`EZAudio` currently offers four components that encompass a wide range of audio functionality. In addition to the functional aspects of these components such as pulling audio data, reading/writing from files, and performing playback they also take special care to hook into the interface components to allow developers to display visual feedback (see the Interface Components below).
@@ -474,7 +465,6 @@ Provides an audio waveform plot that uses CoreGraphics to perform the drawing. O
####Creating An Audio Plot
You can create an audio plot in the interface builder by dragging in a UIView on iOS or an NSView on OSX onto your content area. Then change the custom class of the UIView/NSView to `EZAudioPlot`.
See full Getting Started page for how to: http://syedharisali.com/projects/EZAudio/getting-started
Alternatively, you can could create the audio plot programmatically
@@ -539,7 +529,6 @@ Provides an audio waveform plot that uses OpenGL to perform the drawing. The API
####Creating An OpenGL Audio Plot
You can create an audio plot in the interface builder by dragging in a UIView on iOS or an NSOpenGLView on OSX onto your content area. Then change the custom class of the UIView/NSView to `EZAudioPlotGL`.
See full Getting Started page for how to: http://syedharisali.com/projects/EZAudio/getting-started
Alternatively, you can could create the `EZAudioPlotGL` programmatically
```objectivec