0

In my app, I am trying to record on one device, transmit it and play it back on an other device. I want to animate the sound levels on both the recording device and the Playback device.

Most of the code I have used for recording, playing back and animation is from the SpeakHere sample App.

I have two differences though:

  • I have the additional overhead of transmitting over the network.
  • I an trying to do the horizontal animation with and image(shown below) instead of the colored bands as in SpeakHere

Animation

I am recording and transmitting on a separate dispatch queue(GCD) and the same for receiving and playing back.

  • My first problem is: when I introduce the animation, the receiving and playback becomes very slow and the AudioQueue goes silent.
  • My next problem is with setting a clear background to the LevelMeter view. If I do that then the animation is garbled. Not sure how the animation is connected to the background color.

Below is my version of (not so elegantly modified) drawRect from the SpeakHere example. Please advice on any mistakes I may have made.

My understanding is that I cannot use another thread here for the animation because of UIKit. If not, please correct me.

- (void)drawRect:(CGRect)rect
{
        //();
    CGContextRef cxt = NULL;
    cxt = UIGraphicsGetCurrentContext();

    CGColorSpaceRef cs = NULL;
    cs = CGColorSpaceCreateDeviceRGB();

    CGRect bds;


    if (_vertical)
    {
        CGContextTranslateCTM(cxt, 0., [self bounds].size.height);
        CGContextScaleCTM(cxt, 1., -1.);
        bds = [self bounds];
    } else {
        CGContextTranslateCTM(cxt, 0., [self bounds].size.height);
        CGContextRotateCTM(cxt, -M_PI_2);
        bds = CGRectMake(0., 0., [self bounds].size.height, [self bounds].size.width);
    }

    CGContextSetFillColorSpace(cxt, cs);
    CGContextSetStrokeColorSpace(cxt, cs);

    if (_numLights == 0)
    {
        int i;
        CGFloat currentTop = 0.;

        if (_bgColor)
        {
            [_bgColor set];
            CGContextFillRect(cxt, bds);
        }

        for (i=0; i<_numColorThresholds; i++)
        {
            LevelMeterColorThreshold thisThresh = _colorThresholds[i];
            CGFloat val = MIN(thisThresh.maxValue, _level);

            CGRect rect = CGRectMake(
                                     0, 
                                     (bds.size.height) * currentTop, 
                                     bds.size.width, 
                                     (bds.size.height) * (val - currentTop)
                                     );

            [thisThresh.color set];
            CGContextFillRect(cxt, rect);

            if (_level < thisThresh.maxValue) break;

            currentTop = val;
        }

        if (_borderColor)
        {
            [_borderColor set];
            CGContextStrokeRect(cxt, CGRectInset(bds, .5, .5));
        }

    } 
    else 
    {
        int light_i;
        CGFloat lightMinVal = 0.;
        CGFloat insetAmount, lightVSpace;
        lightVSpace = bds.size.height / (CGFloat)_numLights;
        if (lightVSpace < 4.) insetAmount = 0.;
        else if (lightVSpace < 8.) insetAmount = 0.5;
        else insetAmount = 1.;

        int peakLight = -1;
        if (_peakLevel > 0.)
        {
            peakLight = _peakLevel * _numLights;
            if (peakLight >= _numLights) peakLight = _numLights - 1;
        }

        for (light_i=0; light_i<_numLights; light_i++)
            {
                CGFloat lightMaxVal = (CGFloat)(light_i + 1) / (CGFloat)_numLights;
                CGFloat lightIntensity;
                CGRect lightRect;
                UIColor *lightColor;

                if (light_i == peakLight)
                {
                    lightIntensity = 1.;
                } 
                else 
                {
                    lightIntensity = (_level - lightMinVal) / (lightMaxVal - lightMinVal);
                    lightIntensity = LEVELMETER_CLAMP(0., lightIntensity, 1.);
                    if ((!_variableLightIntensity) && (lightIntensity > 0.)) lightIntensity = 1.;
                }

                lightColor = _colorThresholds[0].color;
                int color_i;
                for (color_i=0; color_i<(_numColorThresholds-1); color_i++)
                {
                    LevelMeterColorThreshold thisThresh = _colorThresholds[color_i];
                    LevelMeterColorThreshold nextThresh = _colorThresholds[color_i + 1];
                    if (thisThresh.maxValue <= lightMaxVal) lightColor = nextThresh.color;
                }

                lightRect = CGRectMake(
                                       0., 
                                       bds.size.height * ((CGFloat)(light_i) / (CGFloat)_numLights), 
                                       bds.size.width,
                                       bds.size.height * (1. / (CGFloat)_numLights)
                                       );
                lightRect = CGRectInset(lightRect, insetAmount, insetAmount);

                if (_bgColor)
                {
                    [_bgColor set];
                    CGContextFillRect(cxt, lightRect);
                }

                UIImage* image = [UIImage imageNamed:@"Pearl.png"];
                CGImageRef imageRef = image.CGImage;


                if (lightIntensity == 1.)
                {
                    CGContextDrawImage(cxt, lightRect, imageRef);

                    [lightColor set];
                    //CGContextFillRect(cxt, lightRect);
                } else if (lightIntensity > 0.) {
                    CGColorRef clr = CGColorCreateCopyWithAlpha([lightColor CGColor], lightIntensity);
                    CGContextSetFillColorWithColor(cxt, clr);
                    //CGContextFillRect(cxt, lightRect);
                    CGContextDrawImage(cxt, lightRect, imageRef);

                    CGColorRelease(clr);
                }

                if (_borderColor)
                {
                    [_borderColor set];
                    CGContextStrokeRect(cxt, CGRectInset(lightRect, 0.5, 0.5));
                }

                lightMinVal = lightMaxVal;
            }       
    }

    CGColorSpaceRelease(cs);
}
4

1 に答える 1

1

描画が遅すぎる可能性があり、Audio Queue コールバックへのリアルタイム応答要件に干渉する可能性があります。

しかし、ほとんどが静止画像の束を描いているので、ドットをそれぞれ別の画像ビューに配置することを検討することをお勧めします。drawRect コードをまったく使用せずに、サブビューを非表示または非表示にするだけで、表示されるドットの数を制御できます。

于 2012-07-11T20:06:38.733 に答える