Oscillator出力を計算する
旧バージョンではOscillator出力を計算するメソッドは以下の様になっていました。
- (double)output:(double)normalizedPhase
{
return amplitude*sin(2*pi*(frequency*normalizedPhase + normalizedPhaseLag));
}
引数のnormalizedPhaseは0から2πまで変化する位相を0から1までに規格化した値です。同様にnormalizedPhaseLagは位相のずれであるphaseLagを規格化した値です。
前はパラメータの値がインスタンス変数に入っていたので、インスタンス変数をそのまま使って計算すればよかったのですが、今はそうはいきません。アクセサメソッドを使って読み出す必要があります。
また以前は円周率πの値をインスタンス変数に予め入れておいたのですが、面倒なのでマクロで対応する事にします。以下のマクロをOscillatorCD.mに追加します。
#define PI acos(-1)
normalizedPhaseLagはphaseLagを変更する際に一緒に変更していたのですが、インスタンス変数を用意するのはやめて都度計算する事にします。
するとoutput:メソッドは以下の様になります
//
// OscillatorCD.m
//
- (double)output:(double)normalizedPhase
{
int amplitude = [[self amplitude] intValue];
int frequency = [[self frequency] intValue];
double normalizedPhaseLag = [[self phaseLag] intValue]/360.0;
return amplitude*sin(2*PI*(frequency*normalizedPhase + normalizedPhaseLag));
}
波形を更新する
波形を更新するメソッドupdateWaveformは、旧バージョンではこうなっていました。 normalizedPhaseを0から1まで変化させて発振器出力を計算し、その結果をつなげているわけです。
- (void)updateWaveform
{
int i;
int resolution = [mixer resolution];
double output,normalizedPhase;
NSBezierPath *path = [NSBezierPath bezierPath];
for(i=0;i<resolution;i++)
{
normalizedPhase = i/(double)resolution;
output = [self output:normalizedPhase];
if(i == 0)
[path moveToPoint:NSMakePoint(i,output)];
else
[path lineToPoint:NSMakePoint(i,output)];
}
[self setWaveform:path];
}
ここでmixerからresolutionというパラメータを得ていますが、ミキサーはいずれ追加するクラスではあるものの、まだ存在しません。そこで、ここは後で修正する事にして、とりあえず固定値にしておきます。
//
// OscillatorCD.m
//
- (void)updateWaveform
{
int i;
int resolution = 200;
double output,normalizedPhase;
NSBezierPath *path = [NSBezierPath bezierPath];
for(i=0;i<resolution;i++)
{
normalizedPhase = i/(double)resolution;
output = [self output:normalizedPhase];
if(i == 0)
[path moveToPoint:NSMakePoint(i,output)];
else
[path lineToPoint:NSMakePoint(i,output)];
}
[self setWaveform:path];
}
updateWameformメソッドは他のクラスからも呼び出される事になる予定なので、インターフェイスファイルに追加しておきます。
//
// OscillatorCD.h
//
#import <CoreData/CoreData.h>
#import "RMGRoot.h"
@interface OscillatorCD : RMGRoot
{
}
- (void)updateWaveform;
- (NSNumber *)amplitude;
- (void)setAmplitude:(NSNumber *)value;
- (NSNumber *)frequency;
- (void)setFrequency:(NSNumber *)value;
- (NSNumber *)phaseLag;
- (void)setPhaseLag:(NSNumber *)value;
- (NSBezierPath *)waveform;
- (void)setWaveform:(NSBezierPath *)value;
@end
Setterで波形を更新する
パラメータが変更された時に波形を更新したいので、OscillatorパラメータのSetterで、波形を更新するメソッドを呼び出します。
//
// OscillatorCD.m
//
- (void)setAmplitude:(NSNumber *)value
{
[self setValue:value forKey:@"amplitude" action:@"setAmplitude"];
[self updateWaveform];
}
- (void)setFrequency:(NSNumber *)value
{
[self setValue:value forKey:@"frequency" action:@"setFrequency"];
[self updateWaveform];
}
- (void)setPhaseLag:(NSNumber *)value
{
[self setValue:value forKey:@"phaseLag" action:@"setPhaseLag"];
[self updateWaveform];
}
awakeFromInsertとawakeFromFetch
属性の初期値はモデリングツールでデフォルト値を設定できるので、わざわざここで初期化コードを書く必要はありません。ただしwaveform属性はデータ型を未定義としているので、デフォルト値がありません。したがって初期化のためのコードが必要です。
awakeFromFetchは管理対象オブジェクトが永続ストアから読み込まれた時に呼び出されます。したがって「一時」がチェックされていない属性は永続ストアに保存されていた値がセットされており、初期化する必要はありません。
「一時」がチェックされている属性は、ここで適切な値で初期化する必要があります。Oscillatorのwaveform属性は一時がチェックされているのでawakeFromFetchで初期化します。
awakeFromInsertとawakeFromFetchで初期化を実行
awakeFromInsertでもawakeFromFetchでもwaveform属性の初期化が必要です。そこでcommonAwakeというメソッドを作って、そこで共通の初期化処理を実行します。
waveformを更新するにはupdateWaveformメソッドを呼びだすだけでOKです。よってOscillatorの初期化コードは以下の様になります。
重要事項としてデベロッパドキュメントに載っていますが、サブクラスは自分の初期化コードを実行する前にスーパークラスのawakeFromInsertを呼び出さないといけません。これはawakeFromFetchでも同じです。
//
// OscillatorCD.m
//
#pragma mark -
#pragma mark Initializer
- (void)commonAwake
{
[self updateWaveform];
}
- (void)awakeFromInsert
{
[super awakeFromInsert];
[self commonAwake];
}
- (void)awakeFromFetch
{
[super awakeFromFetch];
[self commonAwake];
}

ホーム
前へ