ならば

音とかで遊んでいたログ

シェパードトーン

無限音階

聴覚の錯覚の有名な例に、音の高さが上昇(または下降)し続けるように聴こえる無限音階*1がある。無限といっても音高が直線的に上がり続けるというよりは、短時間だとどの区間でも音高が上がっているように聴こえるけど気付いたら以前と同じ高さに戻っているという感覚。つまり実際には循環性がある。これと似た感覚を視覚的に得られるものには、理容店のサインポールエッシャーの「上昇と下降」の元ネタになったペンローズの階段がある。

元々音の高さの知覚には、周波数が大きいほど高く聴こえるという単純な要素以外に、循環的な性質がある。例えば、ドレミファソラシまで行ったら次は(オクターブ上だけど)またドに着くという感じ。高さも合わせて考えると、らせん階段みたいなイメージかな。無限音階ではこの循環性を利用することで、実際には同じところを繰り返しているだけなのに聴く人には上昇し続けているかのような印象を与えられる。ただし、普通に同じ「ドレミファソラシ」を延々と繰り返しても、「シ」の次の「ド」で音高が落ちることがはっきり聴き取れてしまう。そこでこの落差の部分を消すために、周波数から感じられる音の高さをぼかしたシェパードトーンという音を使う。

シェパードトーンは、オクターブ間隔で離れたいくつかのサイン波の合成で、それぞれのサイン波の音量は山の形のように中央を大きく、すそに行くほど小さく設定する。一番低い音と高い音は聴こえないほど小さい音量。
          
上のグラフでいうと、赤い線が各成分(サイン波)で、山の形をした曲線が周波数に対する音量の大きさを決める。こういう構成にすると、音の循環的な要素(例えば「ド」という感覚)を残したまま周波数的な高さはぼかされる。グラフで、赤い線の列を右に動かすことは音階を上がることに対応する。そのままずーっと右に動かしていくと、ちょうど元の状態から1オクターブ右にずれた状態になる。山のすそにある成分は聴こえないので実際にヒトが聴き取れる音としては元の状態と同じものになる。だからこうなる直前に元の状態に戻して、また右に動かしていく。これを延々と繰り返すと、音高がいつ下がったのかをはっきりさせずに、音階を上がり続けることができる。

という原理を基に作ったChucKのプログラム。音量を決める山の形にはガウス関数を使った。

7 => int n;
SinOsc tone[n];
ADSR e => dac;
for (int i; i < n; i++) tone[i] => e;
.7 => e.gain;
e.set(10::ms, 200::ms, .9, 100::ms);

fun float gauss(float x, float a, float b, float c)
{
    return a * Math.exp( -(x-b)*(x-b) / (2*c*c) );
}

fun void setShepardTone(float base, float peak, float peakGain)
{
    int j;
    for (int i; i < n; i++) {
        i - n/2 => j;
        Std.mtof(base + 12 * j) => tone[i].freq;
        gauss(base / 12 + j, peakGain, peak / 12, .8) => tone[i].gain;
    }
}

[60, 62, 64, 65, 67, 69, 71] @=> int scale[];
for (0 => int i; ; (i + 1) % scale.cap() => i) {
    setShepardTone(scale[i], 65.5, .8);
    1 => e.keyOn;
    800::ms => now;
    1 => e.keyOff;
    800::ms => now;
}

録音したもの(音が大きすぎた)。落差が上手く消せてない。

自分で作ったり他の人が作ったものを聴いたりしてみて錯覚と呼べるほど自然に聴けるものを作るのは難しいことが分かった。試行錯誤できそうな部分。

  • 音量を決める山の形:最終的にはこれが一番効いてくると思う
  • 音程の幅:もっと短く、半音ずつ上昇させるほうがいいようだ
  • 一音の長さ、音の間の空白時間:短期記憶と関係あるだろうから多分長い方が効果的

シェパード‐リセのグリッサンド

無限音階には音高が連続的に変化するバージョンもある。リセはこれを最初に作った人。グリッサンドとは音楽用語で異なる音高の間を連続的に移動する演奏技法のこと。

ChucKのプログラム。汚いけど基本的な考え方はシェパード音階と同じ。あとリバーブを加えてみた。

7 => int n;
SinOsc tone[n];
JCRev r => dac;
.1 => r.mix;
.2 => r.gain;

1.003 => float rate;  // 周波数変化率。1より大きいと上昇、小さいと下降
.9 => float pgain;    // ピークの周波数でのゲイン
540 => float center;  // ピークの周波数
.6 => float width;    // ガウス関数の「幅」
Math.log(center) => float logc;
    
fun float gauss(float x, float a, float b, float c)
{
    return a * Math.exp( -(x-b)*(x-b) / (2*c*c) );
}

int j;
for (int i; i < n; i++) {
    tone[i] => r;
    (rate > 1.0 ? n - i - 1 : i) => j;
    center * Math.pow(2, j - n/2) => tone[i].freq;
}
tone[0].freq() * (rate > 1.0 ? 2. : .5) => float mfreq;
gauss(Math.log(mfreq), pgain, logc, width) => float mingain;
tone[n - 1].freq() => float rightsidefreq;

int leftside;  // 左端のオシレータへのインデックス
float newfreq;
while(true) {
    for (int i; i < n; i++) {
        (rate > 1.0 ? n - i - 1 : i) => j;
        if (j == leftside && tone[j].gain() < mingain) {
            rightsidefreq => newfreq => tone[leftside].freq;
            (leftside + 1) % n => leftside;
        } else {
            tone[j].freq() * rate => newfreq => tone[j].freq;
        }
        gauss(Math.log(newfreq), pgain, logc, width) => tone[j].gain;
    }
    50::ms => now;
}

録音したもの。

全音パラドックス

音高の循環性を利用した錯覚に三全音パラドックスがある。発見者はダイアナ・ドイチュ。このパラドックスは三全音離れた二つのシェパードトーンを使う。それぞれの成分の音量を決める山の形とピークの位置は二つとも同じにする。三全音とは、全音三個分の音程のことで、以下の音程と等しい。

  • 半音六個分
  • 1オクターブの半分

まず準備で前提知識を。伝統的な西洋音楽ではオクターブの中に12個の半音がある(十二平均律)。そのうち7個には固有の音名が付けられていて、英語の場合は下から順に、C, D, E, F, G, A, B、となる。残りの5個の音は、これらに変化記号を付けて表される。今回は12個の音を、C, C♯, D, D♯, E, F, F♯, G, G♯, A, A♯, B、と表すことにする。オクターブの違いを無視して同じ音名の音をまとめたものをピッチクラスという。各ピッチクラス間の音程が等しく、また循環性のため、時計の文字盤のように全てのピッチクラスを円状に並べて図示することがある。
          
時計回りに進むと音高の上昇、反時計回りなら下降を意味する。準備完了。

音名の異なる二つのシェパードトーンを連続して鳴らすと、一番目に鳴らした音に比べて音高が上がったか下がったかのどちらかに聴こえる。どっちに聴こえるかは、円周上の一番目の音からスタートして、どちら向きに進む方が二番目の音に近いかで決まるらしい。例えば、一番目の音がCで二番目がEなら時計回りに進んだ方が近いので音高は上がったように聴こえる、ということ。でもこの説だと、三全音離れた音の場合、ちょうど円周の反対側にあってどちらからも等距離なので、聴こえ方が決まらないことになる。ドイチュは実験で、実際にはどちらに聴こえるかがはっきり決まる音名の組合せがあって、しかもそれは人によって違うことを明らかにした。この奇妙な現象のためにパラドックスと呼ばれる。ドイチュはこの現象の理由について、人はそれぞれ心の中でピッチクラスに高低を付けて円状に並べていて、その並びに従ってどちらに聴こえるかを決めるのではないか、と説明している。高低を付けて並べるというのは、図の上側(時計の12時方向)にあるピッチクラスが高く知覚されるということ。例えば上にある図と同じものを心の中に持っている人は C-F♯ の組合せはほぼ確実に音高が下がったように聴こえる。一方で A-D♯ の場合は並びの高さが同じなので安定せずに、その時々で上がったり下がったり聴こえる。

面白い現象なので、自分の心の中の図を調べたくなった。シェパード音階のプログラムを流用して実験。二つのシェパードトーンの組合せをランダムに120回鳴らして、ある組合せで音高が下がったように聴こえたとき被験者がスペースキーを押せばそれをカウントしておいて、最後に統計を出力するようなプログラム。厳密な実験ではないけど*2、シェパードトーンで使う山の形とかピークの位置を変えて何回かやっても似たような結果だったのでそんなに大きなずれはないと思う。

実験結果。一番目の音に対して、三全音離れた二番目の音が下降して聴こえた割合のグラフ。このときはかなり安定して判断できている。
     
上のグラフを基に作ったピッチクラスの並び。
          


高いところに置かれるピッチクラスの種類は人によって全く違うが、この違いは話し言葉に強く依存するらしい。ドイチュや他の研究者の実験には、被験者の育った国や地域によって結果に差が出ることが多いという結果がある。母国語が英語でもカリフォルニアとイギリス南部出身の人では正反対の結果になったとか。日本人でも東と西では違いが出るんじゃないかな。

最後にメモ。ヒトの知覚には残効という現象が起こる。有名な例としては、ある方向に動くものを長い間見た直後に静止したものを見ると、それが以前見ていた運動と逆方向にわずかに動いて見えるという、視覚の運動残効(motion aftereffect)がある。同じように、ピッチクラスの並びにも運動残効があるらしい。上昇するシェパード音階をずっと聴いた直後は、一時的に心の中の図が反時計回りに少しだけ回転するため、三全音パラドックスの実験結果が変わるようだ。詳しくは、Tritone Paradox and Spectral-Motion AfterEffectsに書いてある。


ステレオの錯覚に比べれば、三全音パラドックスは応用しやすそう。シェパードトーンと転調を利用すれば人によって聴こえ方の異なる音楽が作れるような気がする。

*1:発見者の名前からシェパード音階とも呼ばれる

*2:そもそもこういう実験の正しいやり方を知らない