rewrote EZAudioPlayer to use new EZOutput, added notifications, added NSCopying protocol to EZAudioFile, updated play file examples for iOS and Mac

This commit is contained in:
Syed Haris Ali
2015-06-30 02:11:07 -07:00
parent ab9fb5b9bd
commit 6ea04c0f7b
9 changed files with 683 additions and 499 deletions
@@ -149,8 +149,8 @@
<connections>
<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="positionSlider" destination="Oc2-kU-kAJ" id="ZBM-XQ-gzp"/>
<outlet property="rollingHistorySlider" destination="2qJ-Va-Qht" id="8rE-j3-utb"/>
<outlet property="view" destination="PED-9r-Xub" id="Xxb-En-D2X"/>
<outlet property="volumeSlider" destination="d3R-ct-df2" id="pAW-BF-AFa"/>
</connections>
@@ -16,79 +16,104 @@
*/
#define kAudioFileDefault [[NSBundle mainBundle] pathForResource:@"simple-drum-beat" ofType:@"wav"]
/**
Using the EZOutputDataSource to provide output data to the EZOutput component.
*/
@interface PlayFileViewController : UIViewController <EZAudioFileDelegate,
EZOutputDataSource,
EZOutputDelegate>
//------------------------------------------------------------------------------
#pragma mark - PlayFileViewController
//------------------------------------------------------------------------------
#pragma mark - Components
/**
The EZAudioFile representing of the currently selected audio file
The PlayFileViewController will demonstrate how to play an audio file and plot
the audio data in real-time.
*/
@interface PlayFileViewController : UIViewController <EZAudioPlayerDelegate>
//------------------------------------------------------------------------------
#pragma mark - Components
//------------------------------------------------------------------------------
/**
An EZAudioFile that will be used to load the audio file at the file path specified
*/
@property (nonatomic, strong) EZAudioFile *audioFile;
//------------------------------------------------------------------------------
/**
The EZOutput representing the output currently being used to play the audio file.
An EZAudioPlayer that will be used for playback
*/
@property (nonatomic, strong) EZOutput *output;
@property (nonatomic, strong) EZAudioPlayer *player;
//------------------------------------------------------------------------------
/**
The CoreGraphics based audio plot
*/
@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;
//------------------------------------------------------------------------------
/**
A slider to indicate the current frame position in the audio file
*/
@property (nonatomic, weak) IBOutlet UISlider *framePositionSlider;
@property (nonatomic, weak) IBOutlet UISlider *positionSlider;
//------------------------------------------------------------------------------
/**
A slider to indicate the current rolling history length of the audio plot.
A slider to indicate the 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
*/
@property (nonatomic,assign) BOOL eof;
//------------------------------------------------------------------------------
#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)
*/
- (IBAction)changePlotType:(id)sender;
//------------------------------------------------------------------------------
/**
Changes the length of the rolling history of the audio plot.
*/
- (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.
*/
- (IBAction)play:(id)sender;
//------------------------------------------------------------------------------
/**
Seeks to a specific frame in the audio file.
*/
- (IBAction)seekToFrame:(id)sender;
//------------------------------------------------------------------------------
@end
@@ -20,53 +20,31 @@
- (void)viewDidLoad
{
[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
// 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;
//
// Create an EZOutput instance
//
self.output = [EZOutput outputWithDataSource:self];
self.output.delegate = self;
//
// Customize UI controls
// Create the audio player
//
self.volumeSlider.value = [self.output volume];
self.rollingHistorySlider.value = [self.audioPlot rollingHistoryLength];
self.player = [EZAudioPlayer audioPlayer];
self.player.delegate = self;
self.player.shouldLoop = YES;
//
// Try opening the sample file
// Customize UI components
//
self.rollingHistorySlider.value = (float)[self.audioPlot rollingHistoryLength];
/*
Try opening the sample file
*/
[self openFileWithFilePathURL:[NSURL fileURLWithPath:kAudioFileDefault]];
}
@@ -103,53 +81,56 @@
- (void)changeVolume:(id)sender
{
float value = [(UISlider *)sender value];
[self.output setVolume:value];
[self.player setVolume:value];
}
//------------------------------------------------------------------------------
- (void)openFileWithFilePathURL:(NSURL *)filePathURL
{
// Stop playback
[self.output stopPlayback];
//
// Create the EZAudioPlayer
//
self.audioFile = [EZAudioFile audioFileWithURL:filePathURL];
self.audioFile = [EZAudioFile audioFileWithURL:filePathURL delegate:self];
self.eof = NO;
//
// Update the UI
//
self.filePathLabel.text = filePathURL.lastPathComponent;
self.framePositionSlider.maximumValue = (float)self.audioFile.totalFrames;
// Set the input format from the EZAudioFile on the output
[self.output setInputFormat:[self.audioFile clientFormat]];
self.positionSlider.maximumValue = (float)self.audioFile.totalFrames;
self.volumeSlider.value = [self.player volume];
//
// Plot the whole waveform
//
self.audioPlot.plotType = EZPlotTypeBuffer;
self.audioPlot.shouldFill = YES;
self.audioPlot.shouldMirror = YES;
__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];
}];
//
// Play the audio file
//
[self.player setAudioFile:self.audioFile];
}
//------------------------------------------------------------------------------
- (void)play:(id)sender
{
if (![self.output isPlaying])
if ([self.player isPlaying])
{
if (self.eof)
{
[self.audioFile seekToFrame:0];
}
[self.output startPlayback];
[self.player pause];
}
else
{
[self.output stopPlayback];
[self.player play];
}
}
@@ -157,7 +138,39 @@
- (void)seekToFrame:(id)sender
{
[self.audioFile seekToFrame:(SInt64)[(UISlider *)sender value]];
[self.player seekToFrame:(SInt64)[(UISlider *)sender value]];
}
//------------------------------------------------------------------------------
#pragma mark - EZAudioPlayerDelegate
//------------------------------------------------------------------------------
- (void) audioPlayer:(EZAudioPlayer *)audioPlayer
playedAudio:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
inAudioFile:(EZAudioFile *)audioFile
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.audioPlot updateBuffer:buffer[0]
withBufferSize:bufferSize];
});
}
//------------------------------------------------------------------------------
- (void)audioPlayer:(EZAudioPlayer *)audioPlayer
updatedPosition:(SInt64)framePosition
inAudioFile:(EZAudioFile *)audioFile
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf.positionSlider.touchInside)
{
weakSelf.positionSlider.value = (float)framePosition;
}
});
}
//------------------------------------------------------------------------------
@@ -186,73 +199,6 @@
self.audioPlot.shouldMirror = YES;
}
//------------------------------------------------------------------------------
#pragma mark - EZAudioFileDelegate
//------------------------------------------------------------------------------
- (void)audioFile:(EZAudioFile *)audioFile
updatedPosition:(SInt64)framePosition
{
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf.framePositionSlider.touchInside)
{
weakSelf.framePositionSlider.value = (float)framePosition;
}
});
}
//------------------------------------------------------------------------------
#pragma mark - EZOutputDataSource
//------------------------------------------------------------------------------
- (OSStatus) output:(EZOutput *)output
shouldFillAudioBufferList:(AudioBufferList *)audioBufferList
withNumberOfFrames:(UInt32)frames
timestamp:(const AudioTimeStamp *)timestamp
{
if (self.audioFile)
{
UInt32 bufferSize;
BOOL eof;
[self.audioFile readFrames:frames
audioBufferList:audioBufferList
bufferSize:&bufferSize
eof:&eof];
if (eof)
{
[self.audioFile 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(), ^{
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];
}
});
}
//------------------------------------------------------------------------------
@end