iPhone - 获取当前点的音频幅度

iPhone - get amplitude of audio at current point

首先:我对音频处理了解不多。我知道使用 Core Audio,您可以获得有关 正在播放 曲目的信息。

我的目标是在 SpriteKit 中有一个节点,当前来自 iTunes 的歌曲的 amplitude/loudness 是它的音阶(例如,音阶应该在 1.0 最大声和 0.0 在最安静的时候)。

我可以进行节点编程(将 xScaleyScale 设置为 float amp)。我的问题涉及获取 amp 的值。

这是我的代码:

AVAudioPlayer *somePlayer = [AVAudioPlayer new];
__autoreleasing NSError* error;
somePlayer = [somePlayer initWithContentsOfURL:[[[MPMusicPlayerController systemMusicPlayer] nowPlayingItem] valueForProperty:MPMediaItemPropertyAssetURL] error:&error];
somePlayer.currentTime = [[MPMusicPlayerController systemMusicPlayer] currentPlaybackTime];
somePlayer.volume = 0;
[somePlayer play];
[somePlayer setMeteringEnabled:YES];
[somePlayer updateMeters];
NSMutableArray* amps = [NSMutableArray array];
if (error != nil) {
    NSLog(@"error: %@", error.debugDescription);
}
for (int i = 0; i < somePlayer.numberOfChannels; i++) {
    [amps addObject:@([somePlayer averagePowerForChannel:i]);
    NSLog(@"Amplitude: %f db for channel %i", [somePlayer averagePowerForChannel:i], i);
}
float amp = 0;
for (NSNumber *x in amps) {
    amp += [x floatValue];
}
amp /= amps.count;
NSLog(@"amp: %f", amp);
// set xScale and yScale to "amp"
[somePlayer stop];

我得到的是 -120 dB 和滞后的恒定输出(这是在我的 update 方法中)。它通常是 60 fps,但在我的 iPhone 上是 10-11 6。知道如何解决这个问题吗?我在网上搜索了整整一个小时,但一无所获。

我不确定我是否正确解释了您的代码,但看起来您可能在每一帧都实例化了您的播放器,这可以解释速度缓慢的原因。您需要提前设置播放器。然后在您的计时器上,在获得 averagePowerForChannel 之前立即调用 updateMeters。我不熟悉 spiteKit,所以我只是将 UIKit 与 viewDidLoad 和一个 displayLink 用于我的计时器。

@interface ViewController (){
    AVAudioPlayer *somePlayer;
    UIView *redView;
    UIView *blueView;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *eggman = [[NSBundle mainBundle]URLForResource:@"Eggman" withExtension:@"mp3"];
    somePlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:eggman error:NULL];
    [somePlayer setMeteringEnabled:YES];
    [somePlayer play];


    [self addViews];
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animateViews)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}


-(void)animateViews{

    [somePlayer updateMeters];
    float left_db = [somePlayer averagePowerForChannel:0];
    float right_db;
    if (somePlayer.numberOfChannels > 1) {
        right_db = [somePlayer averagePowerForChannel:1];
    }
    else{
        right_db = left_db;
    }


    float blueScale = db_to_scale(left_db);
    float redScale = db_to_scale(right_db);
    float vert = self.view.bounds.size.height - 80;

    blueView.center = CGPointMake(blueView.center.x, vert - (vert * blueScale));
    redView.center = CGPointMake(redView.center.x, vert - (vert * redScale));

}
float db_to_scale(float decibles){
    return powf(10, (0.05 * decibles));
}
-(void)addViews{
    blueView = [[UIView alloc]initWithFrame:CGRectMake(80, 80, 80, 80)];
    blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:blueView];

    redView = [[UIView alloc]initWithFrame:CGRectMake(160, 80, 80, 80)];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
}