ならば

音とかで遊んでいたログ

ヨセフスの問題と半音階

ヨセフスの問題の設定で、円形に並ぶn人の人にそれぞれ番号(じゃなくても一意な記号ならなんでもいい)を付けておいて、円から抜けていく順にその番号を並べた列をヨセフスの順列という。順列の末尾は最後まで残る人の番号。


昔同じようなこと書いたが、十二平均律で半音階を構成する音は下の図のようにピッチクラスに基づいて円形に並べることができる(chromatic circle)。
          
この円に対するヨセフスの順列をヨセフスの音列と呼ぶことにする。勝手に。
nは12で固定なので、スキップする間隔mと最初の音を決めればヨセフスの音列がひとつ決まる。たとえば、mが5で最初の音がCの場合、ヨセフスの音列は(F, A♯, D♯, A, E, C, G♯, G, B, D, F♯, C♯)となる。

ヨセフスの音列を鳴らし続けるChucKのプログラム。
mは定数として設定しておく。最初の音をランダムに選んでヨセフスの音列を鳴らすのがワンセット。それを無限ループで繰り返す。ピッチクラスだけだと音高が決まらないのでベースをC4にした。

Wurley piano => dac;
.05 => piano.gain;

12 => int N;
5 => int M;
60 => int BASE;
500::ms => dur T;

while (true) {
    int flag[N];
    N => int survs;
    Std.rand2(0, N - 1) => int p;

    while (survs > 0) {
        0 => int i;
        while (i < M) {
            (p + 1) % N => p;
            if (flag[p] == 0) i++;
        }
        1 => flag[p];
        survs--;
        BASE + p => Std.mtof => piano.freq;
        1 => piano.noteOn;
        T => now;
    }
    5::T => now;  // 最後の音だけ長く鳴らす
}

録音したもの。
Download


可聴版ヨセフスの問題は、mが与えられた後でヨセフスの音列の最初の音を聴いて最後の音を当てるゲーム。円を一周するごとにベースとなる音高がオクターブ上がるという設定にしてもいいかも。