核心图形绘制,不良性能降级

时间:2015-05-14 06:25:38

标签: ios objective-c core-graphics

我正在使用以下核心图形代码在我录制时绘制音频数据的波形。我为大量代码道歉,但在这里(我发现它here):

//
//  WaveformView.m
//
//  Created by Edward Majcher on 7/17/14.
//

#import "WaveformView.h"

//Gain applied to incoming samples
static CGFloat kGain = 10.;

//Number of samples displayed
static int kMaxWaveforms = 80.;

@interface WaveformView ()

@property (nonatomic) BOOL addToBuffer;

//Holds kMaxWaveforms number of incoming samples, 
//80 is based on half the width of iPhone, adding a 1 pixel line between samples
@property (strong, nonatomic) NSMutableArray* bufferArray;

+ (float)RMS:(float *)buffer length:(int)bufferSize;

@end

@implementation WaveformView

- (void)awakeFromNib
{
    [super awakeFromNib];

    self.bufferArray = [NSMutableArray array];
}

-(void)updateBuffer:(float *)buffer withBufferSize:(UInt32)bufferSize
{
    if (!self.addToBuffer) {
        self.addToBuffer = YES;
        return;
    } else {
        self.addToBuffer = NO;
    }

    float rms = [WaveformView RMS:buffer length:bufferSize];

    if ([self.bufferArray count] == kMaxWaveforms) {
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       // [self.bufferArray removeObjectAtIndex:0];
    }

    [self.bufferArray addObject:@(rms * kGain)];

    [self setNeedsDisplay];
}

+ (float)RMS:(float *)buffer length:(int)bufferSize {
    float sum = 0.0;

    for(int i = 0; i < bufferSize; i++) {
        sum += buffer[i] * buffer[i];
    }

    return sqrtf( sum / bufferSize );
}


// *****************************************************

- (void)drawRect:(CGRect)rect
{
    CGFloat midX = CGRectGetMidX(rect);
    CGFloat maxX = CGRectGetMaxX(rect);
    CGFloat midY = CGRectGetMidY(rect);

    CGContextRef context = UIGraphicsGetCurrentContext();

    // Draw out center line
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextSetLineWidth(context, 1.);

    CGContextMoveToPoint(context, 0., midY);
    CGContextAddLineToPoint(context, maxX, midY);

    CGContextStrokePath(context);

    CGFloat x = 0.;

    for (NSNumber* n in self.bufferArray) {
        CGFloat height = 20 * [n floatValue];
        CGContextMoveToPoint(context, x, midY - height);
        CGContextAddLineToPoint(context, x, midY + height);
        CGContextStrokePath(context);

        x += 2;
    }

    if ([self.bufferArray count] >= kMaxWaveforms) {
        [self addMarkerInContext:context forX:midX forRect:rect];
    } else {
        [self addMarkerInContext:context forX:x forRect:rect];
    }
}

- (void)addMarkerInContext:(CGContextRef)context forX:(CGFloat)x forRect:(CGRect)rect
{
    CGFloat maxY = CGRectGetMaxY(rect);

    CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);

    CGContextFillEllipseInRect(context, CGRectMake(x - 1.5, 0, 3, 3));

    CGContextMoveToPoint(context, x, 0 + 3);
    CGContextAddLineToPoint(context, x, maxY - 3);
    CGContextStrokePath(context);

    CGContextFillEllipseInRect(context, CGRectMake(x - 1.5, maxY - 3, 3, 3));
}

@end

因此,当我录制音频时,波形绘制变得越来越紧张,有点像具有糟糕帧速率的游戏。我试过联系这段代码的所有者,但没有运气。我从来没有使用核心图形,所以我试图找出性能如此糟糕的原因。性能开始下降大约2-3秒的音频(波形甚至不会填满屏幕)。

This is a screen shot from the app, the waveform doesn't even contain that much data.

我的第一个问题是,每次调用drawRect时,是否会重绘整个音频历史记录?如果你查看drawRect函数(用星号标记),就会有一个名为CGRect x的变量。这似乎会影响绘制波形的位置(如果将其设置为60而不是0,则从x = 60像素而不是x = 0像素开始)。

从我的viewController中,我传入了存储在self.bufferArray属性中的audioData。因此,当循环遍历绘制数据时,似乎它从0开始并且每次调用drawRect时都会向上运行,这意味着对于添加的每个新音频数据,drawRect都会被调用,它重绘整个波形加上新的音频数据。

如果这是问题,有谁知道如何优化这段代码?我尝试在循环之后清空bufferArray,这样它只包含新数据,但是没有用。

如果这不是问题,是否有任何核心图形专家能够找出问题所在?

我还应该提一下,我注释掉了一段代码(用符号标记@@@),因为我需要整个波形。我不希望它在开始时删除波形片段。 iOS Voice Memos应用程序可以保存音频波形而不会降低性能。

0 个答案:

没有答案