BAD_ACCESS

おもにiOS、ときどき変な電子工作、ガジェット話。

#4 C4で音楽にあわせてオブジェクトを変化させるーC4でAudio Playerをつくる(2)

この記事は「一人アドベントカレンダー2013〜Lonely Advent Calender 2013〜」の4日目の記事です。

前回はC4Sampleを使って音源のrate(再生速度) pan(左右に振る) volume(音量) で遊んでみました。 非常に簡単に音源をいじることができることがお分かりいただけたのではないでしょうか。

今回は、音楽にあわせてビジュアル面を変化させる方法を実装していこうと思います。 実装する機能は以下の2つ、

1.音楽の再生位置をSeekするスライドバーの実装

2.音楽のレベルにあわせて大きさの変わる円の実装

今回もSampleプロジェクトを用意しています。

1.音楽の再生位置をSeekするスライドバーの実装

参考:C4Sample: Current Time (Both)

@implementation C4WorkSpace {
    C4Sample *sample;
    C4Slider *slider;
...

音源とスライダーのメンバ変数を定義します。

-(void)setup {
    sample = [C4Sample sampleNamed:@"C4Loop.aif"];
    sample.loops = YES;
    [sample play];
    
    [self setupSlider];
}

setupメソッドで音源の初期化、スライダーのセットアップを行います。

-(void)setupSlider {
    slider = [C4Slider slider:CGRectMake(0, 0, 368, 44)];
    slider.center = CGPointMake(self.canvas.center.x, self.canvas.height - 100);
    
    [slider runMethod:@"changeCurrentTime:" target:self forEvent:VALUECHANGED];
    
    [self.canvas addSubview:slider];
    [self updateSlider];
}

スライダーを初期化して、最後にupdateSliderメソッドを呼んでいます。

-(void)updateSlider {
    slider.value = sample.currentTime / sample.duration;
    [self runMethod:@"updateSlider" afterDelay:0.01f];
}

updateSliderは0.01秒ごとに呼ばれることになり、その時点での再生位置をスライダーの位置にあらわしています。

-(void)changeCurrentTime:(C4Slider *)aSlider {
    sample.currentTime = aSlider.value * sample.duration;
  
}

スライダーの位置を変化させると、再生位置をスライダーの位置に合わせて変えるメソッドが呼ばれます。

ビルドしてみると正しく再生位置をスライダーでコントロールできるかと思います。

2.音楽のレベルにあわせて大きさの変わる円の実装

@implementation C4WorkSpace {
    C4Sample *sample;
    C4Slider *slider;
    
    //Level Circle
    C4Shape *levelCircle;
    
    //Masked Image
    C4Image *maskedImage;
    
    //Timer
    C4Timer *meterUpdateTimer;
}

音源のレベルに応じて大きくなったり小さくなったりする円、その円でマスクされる画像、音源のレベルを測るためのタイマーをメンバ変数に定義します。

-(void)setup {
    sample = [C4Sample sampleNamed:@"C4Loop.aif"];
    sample.loops = YES;
    
    //metering enable
    sample.meteringEnabled = YES;
    
    [sample play];
    
    [self setupCircle];
    
    [self setupSlider];
    
    meterUpdateTimer = [C4Timer timerWithInterval:1/30.0f target:self method:@"updateMeters" repeats:YES];
    [meterUpdateTimer start];
}

音源はレベルを測定することを有効化するためにmeteringEnabled=YESとしておきます。 あとは円のセットアップと測定タイマーを初期化してスタートします。

-(void)setupCircle
{
    maskedImage = [C4Image imageNamed:@"C4Sky.png"];
    maskedImage.width = self.canvas.width;
    maskedImage.center = self.canvas.center;
    
    levelCircle = [C4Shape ellipse:CGRectMake(0, 0, 240, 240)];
    levelCircle.center = CGPointMake(maskedImage.center.x, maskedImage.height/2) ;
    maskedImage.mask = levelCircle;
    [self.canvas addImage:maskedImage];
}

円のセットアップを行う際に、画像のマスクとして円を設定しておきます。

-(void)updateMeters {
    [sample updateMeters];
    
    CGFloat avg = [C4Math pow:10 raisedTo:0.05 * [sample averagePowerForChannel:0]];
    float scale;
    scale = 0.8 + (avg * 0.3);
    
    [UIView animateWithDuration:1/30.0f animations:^{
        CGAffineTransform myTransform = CGAffineTransformMakeScale(scale, scale);
        levelCircle.transform = myTransform;
        maskedImage.center = self.canvas.center;
        maskedImage.mask = levelCircle;
    }];

}

最後にタイマーの更新によって音源のレベルを測定し、円のスケールを変化させるようにします。

これで、音源の再生位置を自由にSeekして、音源のレベルにあわせて円が大きくなったり小さくなったりするAudio Playerができました!

ソースコードこちら!