I am trying to animate several views (layers) using CAKeyframeAnimation and CAAnimationGroup. Each view to be animated is contained in an array. My idea is to loop through the array where CAKeyframeAnimation instance of each view would be added to an array of animations, which then would be added to the CAAnimationGroup. My goal is to animate each view one after another. As far as I understand I need to use the group in order to have a reference for the beginTime.
I am probably missing something obvious, but my code doesn't work
CAAnimationGroup *cardAnimationGroup = [CAAnimationGroup animation];
cardAnimationGroup.delegate = self;
cardAnimationGroup.removedOnCompletion = NO;
cardAnimationGroup.beginTime = 0.0f;
[cardAnimationGroup setValue:#"animation0" forKey:#"id"];
cardAnimationGroup.duration = 1.2f * [_myViewsArray count];
NSMutableArray *animationsArray = [[NSMutableArray alloc] init];
// Loop through views
for (UIView *cardView in _myViewsArray)
{
NSUInteger index = [_myViewsArray indexOfObject:cardView];
// my target origin
CGFloat yOffset = (-(cardView.frame.origin.y - _middleCardView.frame.origin.y) - index * 2);
CAKeyframeAnimation *translateCardPositionAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.translation.y"];
translateCardPositionAnimation.removedOnCompletion = YES;
//translateCardPositionAnimation.fillMode = kCAFillModeForwards;
translateCardPositionAnimation.beginTime = 1.2f * index;
translateCardPositionAnimation.duration = 1.2f;
translateCardPositionAnimation.values = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:yOffset],
[NSNumber numberWithFloat:yOffset],nil];
translateCardPositionAnimation.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:1.0f],
[NSNumber numberWithFloat:1.2f], nil];
[_containerCardView addSubview:cardView];
[_containerCardView sendSubviewToBack:cardView];
[animationsArray addObject:translateCardPositionAnimation];
[cardView.layer addObject:translateCardPositionAnimation forKey:#"id"];
if (index == [_myViewsArray count]-1) {
[cardAnimationGroup setAnimations:animationsArray];
}
}
Related
I am working on a project in which A video is recorded.When recording is finished, I play video using AVPlayer adding layer to view. Now I want a gif image as adding layer to that view.
I successfully Add gif image as layer, but image is not animated. It is like a static image.I use Library for GIF image.
My code is below
self.avPlayer = [AVPlayer playerWithURL:self.urlstring];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
AVPlayerLayer *videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
videoLayer.frame = self.preview_view.bounds;
videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.preview_view.layer addSublayer:videoLayer];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"02" withExtension:#"gif"];
CALayer *layer = [[CALayer alloc]init];
layer.frame = self.img_gif.bounds;
layer.contents = (id) [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]].CGImage;
[self.preview_view.layer addSublayer:layer];
Please help me with it
Thank you
I have successfully done it. I added my GIF image to layer.
- (CAKeyframeAnimation *)createGIFAnimation:(NSData *)data{
CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)(data), nil);
int frameCount =(int) CGImageSourceGetCount(src);
// Total loop time
float time = 0;
// Arrays
NSMutableArray *framesArray = [NSMutableArray array];
NSMutableArray *tempTimesArray = [NSMutableArray array];
// Loop
for (int i = 0; i < frameCount; i++){
// Frame default duration
float frameDuration = 0.1f;
// Frame duration
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(src,i,nil);
NSDictionary *frameProperties = (__bridge NSDictionary*)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString*)kCGImagePropertyGIFDictionary];
// Use kCGImagePropertyGIFUnclampedDelayTime or kCGImagePropertyGIFDelayTime
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString*)kCGImagePropertyGIFUnclampedDelayTime];
if(delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
} else {
NSNumber *delayTimeProp = gifProperties[(NSString*)kCGImagePropertyGIFDelayTime];
if(delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Make sure its not too small
if (frameDuration < 0.011f){
frameDuration = 0.100f;
}
[tempTimesArray addObject:[NSNumber numberWithFloat:frameDuration]];
// Release
CFRelease(cfFrameProperties);
// Add frame to array of frames
CGImageRef frame = CGImageSourceCreateImageAtIndex(src, i, nil);
[framesArray addObject:(__bridge id)(frame)];
// Compile total loop time
time = time + frameDuration;
}
NSMutableArray *timesArray = [NSMutableArray array];
float base = 0;
for (NSNumber* duration in tempTimesArray){
//duration = [NSNumber numberWithFloat:(duration.floatValue/time) + base];
base = base + (duration.floatValue/time);
[timesArray addObject:[NSNumber numberWithFloat:base]];
}
// Create animation
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:#"contents"];
animation.duration = time;
animation.repeatCount = HUGE_VALF;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.values = framesArray;
animation.keyTimes = timesArray;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.calculationMode = kCAAnimationDiscrete;
return animation;
}
To add image in layer of view write below code
CALayer *layer = [CALayer layer];
layer.frame = self.preview_view.bounds;
CAKeyframeAnimation *animation = [self createGIFAnimation:[NSData dataWithContentsOfURL:url]];
[layer addAnimation:animation forKey:#"contents"];
["YOUR VIEW".layer addSublayer:layer];
Try this with your image view.
CALayer *layer = [CALayer layer];
layer.backgroundColor = [[UIColor whiteColor] CGColor];
layer.contents = (id) [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]].CGImage;
NSURL *url = [[NSBundle mainBundle] URLForResource:#"02" withExtension:#"gif"];
[[self.view layer] addSublayer:layer];
[layer setNeedsDisplay];
[self.view addSubview: animateImageView];
I have a UITableView with a white background, I would like to apply a linear gradient across the tableview cells so that the gradient is one single gradient from the start to end of the tableview see an example below from Adobe Illustrator. Is there a way this can be achieved using Core Graphics?
I actually managed to figure it out, to some extent from this question and help from matt
- (NSArray *)generateCellGradients
{
NSMutableArray *gradientColors = [[NSMutableArray alloc] init];
NSUInteger numberOfIntervals = self.datasource.count;
CGFloat startColorR = 81.0 / 255.0;
CGFloat startColorG = 118.0 / 255.0;
CGFloat startColorB = 214.0 / 255.0;
UIColor *startColor = [UIColor colorWithRed:startColorR
green:startColorG
blue:startColorB
alpha:1.0];
[gradientColors addObject:startColor];
CGFloat endColorR = 0;
CGFloat endColorG = 191.0 / 255.0;
CGFloat endColorB = 120.0 / 255.0;
UIColor *endColor = [UIColor colorWithRed:endColorR
green:endColorG
blue:endColorB
alpha:1.0];
CGFloat intervalR = (endColorR - startColorR) / numberOfIntervals;
CGFloat intervalG = (endColorG - startColorG) / numberOfIntervals;
CGFloat intervalB = (endColorB - startColorB) / numberOfIntervals;
for (NSUInteger i = 0; i < numberOfIntervals; i++) {
startColorR += intervalR;
startColorG += intervalG;
startColorB += intervalB;
UIColor *intervalColor = [UIColor colorWithRed:startColorR green:startColorG blue:startColorB alpha:1.0];
[gradientColors addObject:intervalColor];
}
[gradientColors addObject:endColor];
NSMutableArray *cellGradients = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < gradientColors.count; i++) {
UIColor *startGradientColor = gradientColors[i];
UIColor *endGradientColor;
if (i == gradientColors.count - 1) {
endGradientColor = gradientColors[i];
} else {
endGradientColor = gradientColors[i + 1];
}
NSArray *colors = #[(id)startGradientColor.CGColor, (id)endGradientColor.CGColor];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = colors;
[cellGradients addObject:gradientLayer];
}
return cellGradients;
}
This is how to add it to a subview:
CAGradientLayer *backgroundLayer = self.gradients[indexPath.row];
backgroundLayer.frame = view.bounds;
[view.layer insertSublayer:backgroundLayer atIndex:0];
Here is the result below:
Find below the code to create gradient layer by provide two required colours. You can add this layer to any view. Add this framework #import <QuartzCore/QuartzCore.h> in order to achieve this result.
typedef enum {
GradientType_Linear,
GradientType_Reflected,
}GradientType;
+(CAGradientLayer*) gradientLayerFromColor:(UIColor *)firstColor
secondColor:(UIColor *)secondColor
gradientType:(GradientType)gradientType
{
UIColor *colorStart = firstColor;
UIColor *colorEnd = secondColor;
NSArray *colors;
NSArray *locations;
switch (gradientType) {
case GradientType_Linear:
{
colors = [NSArray arrayWithObjects:(id)colorStart.CGColor, colorEnd.CGColor, nil];
NSNumber *start1 = [NSNumber numberWithFloat:0.0];
NSNumber *stop1 = [NSNumber numberWithFloat:1.0];
locations = [NSArray arrayWithObjects:start1, stop1, nil];
}
break;
case GradientType_Reflected:
{
colors = [NSArray arrayWithObjects:(id)colorStart.CGColor, colorEnd.CGColor, colorEnd.CGColor, colorStart.CGColor, nil];
NSNumber *start1 = [NSNumber numberWithFloat:0.0];
NSNumber *stop1 = [NSNumber numberWithFloat:0.5];
NSNumber *start2 = [NSNumber numberWithFloat:0.5];
NSNumber *stop2 = [NSNumber numberWithFloat:1.0];
locations = [NSArray arrayWithObjects:start1, stop1, start2, stop2, nil];
}
break;
default:
{
colors = [NSArray arrayWithObjects:(id)colorStart.CGColor, colorEnd.CGColor, nil];
NSNumber *start1 = [NSNumber numberWithFloat:0.0];
NSNumber *stop1 = [NSNumber numberWithFloat:1.0];
locations = [NSArray arrayWithObjects:start1, stop1, nil];
}
break;
}
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = colors;
gradientLayer.locations = locations;
return gradientLayer;
}
I have a method which translates a view and optionally scales it while translating. I am using animation groups and adding the required animations as needed. Here are the animation cases working perfectly.
Translation (x or y axis or both) (OK)
Scaling (OK)
Translation while scaling (MOSTLY)
However, doing a translation while scaling works only when the starting scalefactor is 1. When the view is already scaled, I notice most of the transition jumping instead of animating, although the end result of scaling and translation is correct.
I am posting part of the code for clarification. The problem occurs only when previousZoomScale is not 1! I appreciate any directions you can point me to.
-(void)performAnimationForView: (AnimationType)animationType
WithDX: (CGFloat)dx
AndDY: (CGFloat)dy
Scale: (CGFloat)scale
Duration: (CGFloat)duration
{
CABasicAnimation *translateXAnimation = nil, *translateYAnimation = nil, *scaleAnimation = nil;
NSString* animationGroupName;
CGPoint newDxDy;
switch (animationType)
{
case kAnimationTranslateAndScale:
// set animation key
animationGroupName = #"translatescale";
translateXAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
translateXAnimation.repeatCount = 0;
translateXAnimation.autoreverses = NO;
translateXAnimation.removedOnCompletion = NO;
translateXAnimation.fillMode = kCAFillModeForwards;
translateXAnimation.fromValue = [NSNumber numberWithFloat: self.previousDxDy.x]; // previous point we're tranlsating from
translateXAnimation.toValue = [NSNumber numberWithFloat:dx]; // destination point
translateYAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.y"];
translateYAnimation.repeatCount = 0;
translateYAnimation.autoreverses = NO;
translateYAnimation.removedOnCompletion = NO;
translateYAnimation.fillMode = kCAFillModeForwards;
translateYAnimation.fromValue = [NSNumber numberWithFloat: self.previousDxDy.y];
translateYAnimation.toValue = [NSNumber numberWithFloat:dy];
newDxDy = CGPointMake(dx, dy);
self.previousDxDy = newDxDy;
// scaling animation
scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.autoreverses = NO;
scaleAnimation.repeatCount = 0;
scaleAnimation.removedOnCompletion = NO;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.fromValue = [NSNumber numberWithDouble: self.previousZoomScale]; // initial zoom scale
scaleAnimation.toValue = [NSNumber numberWithDouble:scale]; // target scale
self.previousZoomScale = scale;
break;
}
NSMutableArray* animationArray = [[NSMutableArray alloc] initWithObjects: nil];
if (translateXAnimation != nil)
[animationArray addObject: translateXAnimation];
if (translateYAnimation != nil)
[animationArray addObject: translateYAnimation];
if (scaleAnimation != nil)
[animationArray addObject: scaleAnimation];
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.duration = duration;
theGroup.removedOnCompletion = NO;
theGroup.fillMode = kCAFillModeForwards;
theGroup.repeatCount = 0;
theGroup.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear];
theGroup.animations = animationArray;
theGroup.delegate = self;
[theGroup setValue: animationGroupName forKey: #"animationtype"];
[self.backgroundImageView.layer addAnimation: theGroup forKey: animationGroupName];
}
I made this code to create CAKeyframeAnimation but result is not bouncing at all
-(CAKeyframeAnimation *)keyframeBounceAnimationFrom:(NSValue *)from
to:(NSValue *)to
forKeypath:(NSString *)keyPath
withDuration:(CFTimeInterval)duration
{
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
NSMutableArray * valuesArray = [NSMutableArray array];
NSMutableArray * timeKeyArray = [NSMutableArray array];
[self createBounceFrom:from to:to Values:valuesArray keyTimes:timeKeyArray];
[animation setValues:valuesArray];
[animation setKeyTimes:timeKeyArray];
animation.duration = duration;
return animation;
}
-(void)createBounceFrom:(NSValue *)from to:(NSValue *)to Values:(NSMutableArray *)values keyTimes:(NSMutableArray *)keyTimes
{
CGPoint toPoint= [to CGPointValue];
CGFloat offset = 60;
CGFloat duration = 1.0f;
NSUInteger numberOfOscillations= 4;
[values addObject:from];
[keyTimes addObject:[NSNumber numberWithFloat:0.0f]];
//============
//ideally bouncing will depend from starting position to end poisiton as simulating real Dumping Oscillations
//============
for (NSUInteger index= 0; index <numberOfOscillations ; index++)
{
CGPoint viaPoint = CGPointMake(toPoint.x, toPoint.y + offset);
NSValue * via = [NSValue valueWithCGPoint:viaPoint];
[values addObject:via];
//add time consumed for each oscillation
[keyTimes addObject:[NSNumber numberWithFloat:duration]];
// duration = duration - 0.1;
offset = - offset ;
}
[values addObject:to];
[keyTimes addObject:[NSNumber numberWithFloat:0.6]];
}
Here's a great link with some examples of how to use it:
(After some more looking I found this: http://www.cocoanetics.com/2012/06/lets-bounce/ which I think makes a much better bounce, but more advanced. So wont put the code here)
http://www.touchwonders.com/some-techniques-for-bouncing-animations-in-ios/
The example with CAKeyframeAnimation would be: (taken from the link)
-(void)animateGreenBall
{
NSValue *from = #(greenBall.layer.position.y);
CGFloat bounceDistance = 20.0;
CGFloat direction = (greenUp? 1 : -1);
NSValue *via = #((greenUp ? HEIGHT_DOWN : HEIGHT_UP) + direction*bounceDistance);
NSValue *to = greenUp ? #(HEIGHT_DOWN) : #(HEIGHT_UP);
NSString *keyPath = #"position.y";
CAKeyframeAnimation *animation = [self keyframeBounceAnimationFrom:from
via:via
to:to
forKeyPath:keyPath
withDuration:.6];
[greenBall.layer addAnimation:animation forKey:#"bounce"];
[greenBall.layer setValue:to forKeyPath:keypath];
greenUp = !greenUp;
}
-(CAKeyframeAnimation *)keyframeBounceAnimationFrom:(NSValue *)from
via:(NSValue *)via
to:(NSValue *)to
forKeyPath:(NSString *)keyPath
withDuration:(CFTimeInterval)duration
{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
[animation setValues:#[from, via, to, nil]];
[animation setKeyTimes:#[#(0), #(.7), #(1), nil]];
animation.duration = duration;
return animation;
}
I'm trying to plot the decibel values of sound on a graph(CPScatterPlot) using coreplot. But the problem is I'm getting the graph with a line that is perpendicular for Y axis, and it's moving up and down on the Y axis with respect to the changes in the decibel values. I need to plot a graph like this.
here is my code:
`
-(void) generateDataSamples
{
samples = [[NSMutableArray alloc]initWithCapacity:NUM_SAMPLES];
for (int i=0; i < NUM_SAMPLES; i++)
{
// peakVal is a variable that holds the decibel value
NSDictionary *sample = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:peakVal],Y_VAL,nil];
[samples addObject:sample];
}
}
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot;
{
return [samples count];
}
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index{
NSDictionary *sample = [samples objectAtIndex:index];
NSDecimalNumber *num = [NSDecimalNumber zero];
if (fieldEnum == CPScatterPlotFieldX)
{
num = (NSDecimalNumber *) [NSDecimalNumber numberWithInt:index + 1];
}
else if (fieldEnum == CPScatterPlotFieldY)
{
return [sample valueForKey:Y_VAL];
}
return num;
}
So, what should I do to get a graph as in the figure above? Please help me, I'm new on here.
And one more, as you can in the above picture, the Y axis labels are placed inside the plot area, how it can be done?
Here is my entire code, please suggest the modifications:
#import "MicBlowViewController.h"
#import "SecondVC.h"
#define DBOFFSET -74.0
#define START_POINT 0.0
#define END_POINT 100.0
#define NUM_SAMPLES 200.0
#define MAX_PEAK 100.0
#define X_VAL #"X_VAL"
#define Y_VAL #"Y_VAL"
#define S_VAL #"S_VAL"
#implementation MicBlowViewController
#synthesize avgLabel, peakLabel,absValue,pageControl;
-(void)reloadData
{
if(!graph)
{
//setting graph
double xAxisStart = START_POINT;
double xAxisLength = END_POINT - START_POINT;
double maxY = 100;//[[samples valueForKeyPath:#"#max.Y_VAL"] doubleValue];
double yAxisStart = START_POINT;
double yAxisLength = maxY+3;
xVal=START_POINT+0.1;
hostingView = [[CPGraphHostingView alloc] initWithFrame:CGRectMake(0, 79, 320, 361)];
[self.view addSubview:hostingView];
graph = [[CPXYGraph alloc] initWithFrame:CGRectMake(0, 79, 320, 361)];
hostingView.hostedGraph = graph;
CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
[graph applyTheme:theme];
graph.paddingTop = 0.0;
graph.paddingBottom = 0.0;
graph.paddingLeft = 0.0;
graph.paddingRight = 0.0;
[[graph defaultPlotSpace] setAllowsUserInteraction:TRUE];
CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
axisSet.yAxis.labelOffset=0.1;
CPXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPDecimalFromDouble(10.0);
x.orthogonalCoordinateDecimal = CPDecimalFromInteger(0);
x.minorTicksPerInterval = 1;
CPXYAxis *y = axisSet.yAxis;
y.majorIntervalLength=CPDecimalFromDouble(10.0);
y.orthogonalCoordinateDecimal = CPDecimalFromInteger(0);
y.minorTicksPerInterval = 1;
y.tickDirection = CPSignPositive;
y.labelAlignment = CPAlignmentLeft;
y.alternatingBandFills = [NSArray arrayWithObjects:[[CPColor whiteColor] colorWithAlphaComponent:0.1], [NSNull null], nil];
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromDouble(xAxisStart)
length:CPDecimalFromDouble(xAxisLength)];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromDouble(yAxisStart)
length:CPDecimalFromDouble(yAxisLength)];
CPScatterPlot *dataSourceLinePlot = [[CPScatterPlot alloc] init];
dataSourceLinePlot.dataSource = self;
//[dataSourceLinePlot insertDataAtIndex:[samplesY count]-1 numberOfRecords:1];
CPMutableLineStyle *lineStyle = [[dataSourceLinePlot.dataLineStyle mutableCopy] autorelease];
lineStyle.lineWidth = 2.f;
lineStyle.lineColor = [CPColor cyanColor];
dataSourceLinePlot.dataLineStyle = lineStyle;
[graph addPlot:dataSourceLinePlot];
[dataSourceLinePlot release];
[graph release];
[hostingView release];
}
}
- (void)generateData
{
// if (plotData == nil) {
NSMutableArray *contentArray = [NSMutableArray array];
for (NSUInteger i = 0; i < 200; i++) {
//double test = (double)[peakLabel.text doubleValue];
absValue.text =[NSString stringWithFormat:#"%.2f",peakVal];
id x = [NSDecimalNumber numberWithDouble:1.0 + i ];
id y = [NSDecimalNumber numberWithDouble:peakVal * rand()/(double)RAND_MAX + 0.05];
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y", nil]];
}
plotData = [contentArray retain];
//}
}
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot ;
{
return [plotData count];
}
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index;
{
NSNumber *num = [[plotData objectAtIndex:index] valueForKey:(fieldEnum == CPScatterPlotFieldX ? #"x" : #"y")];
if (fieldEnum == CPScatterPlotFieldY) {
num = [NSNumber numberWithDouble:[num doubleValue]];
}
return num;
}
- (void)viewDidLoad {
[super viewDidLoad];
pageControl = [[UIPageControl alloc]init];
[pageControl addTarget:self action:#selector(changePage) forControlEvents:UIControlEventValueChanged];
samplesY = [[NSMutableArray alloc]init];
//checking for sound
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
}// else
//NSLog([error description]);
}
- (void)levelTimerCallback:(NSTimer *)timer {
// getting decibel values....
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
NSLog(#"Average input: %f Peak input: %f Low pass results: %f",
[recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);
peakval=fabs([recorder peakPowerForChannel:0]);
double avgval=fabs([recorder averagePowerForChannel:0]);
peakVal=MAX_PEAK - peakval;
avgVal=MAX_PEAK - avgval;
NSLog(#"First: %.2f",peakVal);
avgLabel.text=[NSString stringWithFormat:#"%.2f",avgVal];
peakLabel.text=[NSString stringWithFormat:#"%.2f",peakVal];
if (lowPassResults < 0.95)
NSLog(#"Mic blow detected: %d",lowPassResults);
[self generateData];
[self reloadData];
}
- (IBAction) changePage:(id)sender{
SecondVC *vc = [[SecondVC alloc]init];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:vc animated:YES];
[vc release];
}
- (void)dealloc {
[peakLabel.text release];
[avgLabel.text release];
[samples release];
[levelTimer release];
[recorder release];
[super dealloc];
}
#end
It looks like you're using the same peakVal for every data point. Check the -generateDataSamples method and make sure you're storing the correct values in the samples array. If you already have the data in an array, you can skip that method completely and just do the lookup by index in -numberForPlot:field:recordIndex:.
Also, check the xRange and yRange on the plot space to make sure they fit your data. Remember that plot ranges are like NSRange—they are created using a starting location and length, not start and end values.
To move the labels to the right side of the y-axis, use yAxis.tickDirection = CPTSignPositive;.
Edit in response to the comments
Don't call -generateDataSamples every time you get new data. Instead, add the new value to the samples array. Don't forget to initialize the array before using it for the first time.
NSDictionary *sample = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:peakVal],Y_VAL,nil];
[samples addObject:sample];
Once the data is in the array, tell Core Plot to load only the new point. This will be faster than reloading all of the data every time you update.
[myScatterPlot insertDataAtIndex:(samples.count - 1)
numberOfRecords:1];
You can use the CPTPlot method -deleteDataInIndexRange: to remove old data points if you don't need to keep all of the history in the graph. Don't forget to remove the corresponding point from the samples array also.