FM音源YMF825boardを使った自作MIDI音源に可変周期 パターンも変化できるソフトウェアモジュレーションを実装してみました もともとハードウェアでモジュレーションは掛けれるのですが 複数のボイスを同一音色で鳴らした場合、同じタイミングで変化 します(ストリング系の音色で和音を使った場合とか) 同一音色でも発音したタイミングによってモジュレーションの 掛り方がずれるようにしてみました。
実装
ATmega32U4のタイマ1割り込みを使い各ボイスごとのカウンタを減算させて
32ステップのサインテーブルから読み出した値を周波数補正用のFRACに加算します。
それだけでは面白くないのでサインテーブルから読み出し位置を変化させるための
カウンタを設け、読み出した値でボイスの読み出し位置を変化させてみました
(変数名がおかしいのは後でアセンブラで書き直すため)
ISR(TIMER1_COMPA_vect){
uint8_t i,c,d;
uint8_t work_s,xl;
signed char e;
for(i = 0;i < channelVal;i++){
c = modulation_cnt[i];
if(c != 0){
c--;
if(c != 0){
modulation_cnt[i] = c;
}else{
modulation_cnt[i] = modulation_pitch[i];
work_s = sin_pitch[i];
xl = sin_pointer[i]; //変調用読み出し位置
xl = work_s + xl;
xl &= 0x3f;
sin_pointer[i] = xl;
work_s = sin_tbl_offs[i];
/* 補正値をテーブルから読み込み */
work_s = pgm_read_byte(&(sin_tbl[work_s][xl]));
c = modulation_tblpointer[i]; //テーブル読み出し位置保持用
c = c +work_s+1;
c &= 0x3f;
modulation_tblpointer[i] = c;
d = modulation_depth[i];
e = pgm_read_byte(&(sin_tbl[(int)d][(int)c]));
c = midi_ch[ym825_voice_ch[i].midi_ch].reg_18; //PitchBend hi
d = midi_ch[ym825_voice_ch[i].midi_ch].reg_19;
d = d + e;
if(d & 0x80){ //桁補正処理
if(e>0){
c++;
}else{
c--;
}
}
cli();
if_s_write(0x0b,i);
if_s_write(0x12,c);
if_s_write(0x13,d);
sei();
}
}
}
}
各パラメータの配列は、アセンブラ化した時に連続したアドレスに置いてオフセットアドレッシングでアクセス時間を削るためあえて別々に宣言しています、ただし乗算器を持っているハードウェアの場合構造体の配列にしてもたいして変わらないです。
step=1 depth=31
step=2 depth=10
どこかで見たよう波形です、FM音源の2オペレータ直列アルゴリズムの波形そのもの
こんな複雑なパターンも可能です。
実際に音色に掛けてみたら
弦楽器や残響音などに使うと音色が豊かになってきます。
AVRマイコンはTIMER割り込みの優先度がSPI通信割り込みより高いので
このソースではタイマ割り込みで処理していますが
高速でビブラートをかけるとSPI通信の方が破綻したので
後にタイマカウンタが指定値をオーバーしたらコールするように変更しました。