LoginSignup
0
0

MIDI音源でティンパニのロールを再現する

Last updated at Posted at 2024-02-28

MIDIのサンプリング音源では、ティンパニのロールはロールのサンプリング音が入っているのが一般的です。同じ音量でずっとロールし続けるならそれでもいいですが、クレッシェンドやデクレッシェンドしようとすると、音質は変わらずに音量だけ変化することになるので、強弱の幅が大きいときには不自然な響きになってしまいます。音源によっては、ティンパニ・ロールのクレッシェンド、デクレッシェンドのサンプルも入ってたりするのですが、それだとクレッシェンドやデクレッシェンドのタイミングが調節できません。

ラウンドロビンに対応している音源なら、単発のティンパニ音を適度な間隔で細かく打ちこめば、それっぽく聞こえるのですが、普通に打ちこんだだけだと、途中で曲のテンポが変わるとロールの速度も変化してしまいます。ちょっとの変化なら気にしなくてもいいかもしれませんが、大きめのリタルダンドなんかがあると、最後はモタモタになってしまいます。

なんとかならないかなと思っていたところ、ReaperというDAWなら、jsfxというスクリプトで実現できそうだったので、試しに簡単なスクリプトを作ってみました。このページの最後にあるのがそのスクリプトです。

作成する際に使用した音源はVSCO2 CEというフリーの音源ですが、指定した時間間隔でひたすらノート・オン、オフの信号を出してるだけなので、おそらくどんな音源でも動くでしょう。

ロールの音の大きさは、Expression(CC11)で変えられるようにしたので、デクレッシェンドやクレッシェンドも自由自在です。このとき、Expressionの値を打音のベロシティに置き換えて音を鳴らすようにしているので、(デ)クレッシェンドすればベロシティに合わせてちゃんと音質も変化します。また、ロールの間隔は拍ベースではなく時間ベースなので、テンポを変化させてもロールの細かさには影響しません。

作成したティンパニロールのサンプル

とりあえず作ってみただけの割には、なかなかよくできたので、Reaperを使っている人がどれくらいいるか、またどの程度需要があるかわかりませんが、スクリプトを公開しておきます。

解説

(2024.02.29追加)

このスクリプトですが、ノートのオン・オフに関する処理は@blockwhileループで実施しています。

while (midirecv(ts, msg1, msg2, msg3)) (

while文の中のmidirecv(ts, msg1, msg2, msg3)がMIDI信号の受け取りで、tsはオフセット、msg1はMIDIのステータス、msg2はノート・ナンバーやコントロール・ナンバー、msg3はベロシティやCCの値です。

m = msg1 & 240; 

ループの最初のmsg1 & 240でステータス・メッセージの上位バイトを取り出します。これが9nならノートオン8nならノートオフ、11n (BnH)ならCCです。

以降の処理では、msg2で押されたのがキースイッチに割り当てたキーなのかを判断して、ロールの開始・停止処理、ベロシティの変更を行っています。また、CCの場合はExpression(CC11)かどうかをみています。
MIDIの信号をシンセ側に送る処理は、midisend()で行っています。この関数の引数はmidirecv()と同じです。

なお、while (midirecv(ts, msg1, msg2, msg3)) (...の部分は最初、MIDIキーボードのキーを押し続けている間はずっと処理されるのかと勘違いしていましたが、このループは何らかのMIDI信号を受信した瞬間しか処理されないので、キーを押したとき、離したとき、CCを送ったときのみしか処理されません。なので、このwhile文の中のmidisend(ts,9*16,note,msg3);の部分は、ロール開始時の1発目の音だけを鳴らしていることになります。

それ以外のロールの持続処理は、while文を抜けた後の最後の部分で行っています。

(roll_mode && roll_on) ?(
  counter += inc;
  (counter > 1000) ? (
    counter = 0;
    midisend(ts,8*16,note);
    midisend(ts,9*16,note,vel - velocity_rand + floor(rand(velocity_rand)) );
  );
);

ここで、このスクリプトが実行されるたびカウンターに数値を加えていき、それが閾値を超えたらノートをオフ・オンしんてカウンターをリセットする、の繰り返しです。

なお、ロールの開始と停止は、本当はノートごとにフラグを設定したほうがいいのでしょうが、ここではroll_onという変数1つしか使っていないので、複数の音を同時に鳴らしたとき、いずれか音でノートオフの信号が発生すると、そこでロールはストップします。これはキースイッチについても同様なので、ロール音を発生させる場合には、その音のノートオンより前にキースイッチのキーを離すか、あるいは、ロールが終了するまでキースイッチのキーを押しっぱなしにしておく必要があります。

desc:TimpRoller

slider1:127<0,127,1>Velocity Max
slider2:64<0,127,1>Velocity Min
slider3:2<0,10,1>Velocity Rand

slider4:1.45<1,2>Speed in Velocity Max
slider5:1.8<1,2>Speed in Velocity Min
slider6:5<0,10,1>Speed Rand

slider7:13<-0,127,1{0: C-1,1: C#-1,2: D-1,3: D#-1,4: E-1,5: F-1,6: F#-1,7: G-1,8: G#-1,9: A-1,10: Bb-1,11: B-1,12: C0,13: C#0,14: D0,15: D#0-1,16: E0,17: F0,18: F#0,19: G0,20: G#0,21: A0,22: Bb0,23: B0,24: C1,25: C#1,26: D1,27: D#1,28: E1,29: F1,30: F#1,31: G1,32: G#1,33: A1,34: Bb1,35: B1,36: C2,37: C#2,38: D2,39: D#2,40: E2,41: F2,42: F#2,43: G2,44: G#2,45: A2,46: Bb2,47: B2,48: C3,49: C#3,50: D3,51: D#3,52: E3,53: F3,54: F#3,55: G3,56: G#3,57: A3,58: Bb3,59: B3,60: C4,61: C#4,62: D4,63: D#4,64: E4,65: F4,66: F#4,67: G4,68: G#4,69: A4,70: Bb4,71: B4,72: C5,73: C#5,74: D5,75: D#5,76: E5,77: F5,78: F#5,79: G5,80: G#5,81: A5,82: Bb5,83: B5,84: C6,85: C#6,86: D6,87: D#6,88: E6,89: F6,90: F#6,91: G6,92: G#6,93: A6,94: Bb6,95: B6,96: C7,97: C#7,98: D7,99: D#7,100: E7,101: F7,102: F#7,103: G7,104: G#7,105: A7,106: Bb7,107: B7,108: C8,109: C#8,110: D8,111: D#8,112: E8,113: F8,114: F#8,115: G8,116: G#8,117: A8,118: Bb8,119: B8,120: C9,121: C#9,122: D9,123: D#9,124: E9,125: F9,126: F#9,127: G9}>Roll On Switch
slider8:15<-0,127,1{0: C-1,1: C#-1,2: D-1,3: D#-1,4: E-1,5: F-1,6: F#-1,7: G-1,8: G#-1,9: A-1,10: Bb-1,11: B-1,12: C0,13: C#0,14: D0,15: D#0-1,16: E0,17: F0,18: F#0,19: G0,20: G#0,21: A0,22: Bb0,23: B0,24: C1,25: C#1,26: D1,27: D#1,28: E1,29: F1,30: F#1,31: G1,32: G#1,33: A1,34: Bb1,35: B1,36: C2,37: C#2,38: D2,39: D#2,40: E2,41: F2,42: F#2,43: G2,44: G#2,45: A2,46: Bb2,47: B2,48: C3,49: C#3,50: D3,51: D#3,52: E3,53: F3,54: F#3,55: G3,56: G#3,57: A3,58: Bb3,59: B3,60: C4,61: C#4,62: D4,63: D#4,64: E4,65: F4,66: F#4,67: G4,68: G#4,69: A4,70: Bb4,71: B4,72: C5,73: C#5,74: D5,75: D#5,76: E5,77: F5,78: F#5,79: G5,80: G#5,81: A5,82: Bb5,83: B5,84: C6,85: C#6,86: D6,87: D#6,88: E6,89: F6,90: F#6,91: G6,92: G#6,93: A6,94: Bb6,95: B6,96: C7,97: C#7,98: D7,99: D#7,100: E7,101: F7,102: F#7,103: G7,104: G#7,105: A7,106: Bb7,107: B7,108: C8,109: C#8,110: D8,111: D#8,112: E8,113: F8,114: F#8,115: G8,116: G#8,117: A8,118: Bb8,119: B8,120: C9,121: C#9,122: D9,123: D#9,124: E9,125: F9,126: F#9,127: G9}>Roll Off Switch

in_pin:none
out_pin:none

@init


status=0;
status2=128;
roll_mode = 0;
roll_on = 0;
vel = 64;

velocity_lo= 64;
velocity_hi= 127;
speed_lo= 145;
speed_hi= 180;

speed_rand = 5;
velocity_rand = 2;

memset(status,-1,128);
memset(status2,0,128);

@slider 
velocity_hi=floor(slider1);
velocity_lo=floor(slider2);
velocity_rand=floor(slider3);
speed_hi=slider5*100;
speed_lo=slider4*100;
speed_rand=slider6;
roll_on_key = slider7;
roll_off_key = slider8;

@block
      
while (midirecv(ts, msg1, msg2, msg3)) (
  m = msg1 & 240; 

  (m == 9*16 && msg2 == roll_on_key ) ? (roll_mode = 1):
  (m == 9*16 && msg2 == roll_off_key ) ? (roll_mode = 0):
  (m == 9*16)?
  (
    note = msg2;
    status[note]=0;
    status2[note]=vel;
    midisend(ts,9*16,note,msg3);
    roll_on = 1;
 ) : (m == 8*16 || m == 9*16) ? (
    (m == 8*16)? roll_on = 0;
    note = msg2;
    status[note]=-1;
    status2[note]>0.0 ? (
    midisend(ts,8*16,note); // send note off
      status2[note]=0;
    );
  ) : (m == 11*16)?(
    vel=msg3;
  ):(
    midisend(0,9*16,61,vel); 
  );
);

velocity_diff = velocity_hi - velocity_lo;
speed_diff  = speed_hi - speed_lo;
inc_rt = speed_diff/velocity_diff;

vel < 64 ?(inc = 180):(inc = speed_hi - velocity_diff*inc_rt + rand(speed_rand));

(roll_mode && roll_on) ?(
  counter += inc;
  (counter > 1000) ? (
    counter = 0;
    midisend(ts,8*16,note);
    midisend(ts,9*16,note,vel - velocity_rand + floor(rand(velocity_rand)) );
  );
);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0