ならば

音とかで遊んでいたログ

ジャグリングパターンの可聴化

可聴化する意義がありそうな数列をしばらく探していて、サイトスワップを見つけた。今回はサイトスワップvanilla siteswap)の可聴化。サイトスワップトスジャグリングでボールを投げるパターンを表す数列。定義と性質は、ジャグリングを科学するというサイトにとても分かりやすい解説がある。

サイトスワップについて今回の可聴化のデザインに必要な要点だけ書くと、

  • ジャグリングするときは一定の時間間隔(ビート)で、左手・右手で交互にボールを投げるという前提がある
  • そのとき投げるボールを次回また投げるまでの時間(ビート)をひとつの数値(0から9)で表現する
  • ジャグリングするときは数値に従って順に投げていって、数列の最後までいったら最初に戻って繰り返す

くらいでいいかな。
例えば「3」というサイトスワップに従って左手からボールを投げる場合、

  1. 空中に約3ビートあるようにボールAを左手から右側に投げる
  2. 空中に約3ビートあるようにボールBを右手から左側に投げる
  3. 空中に約3ビートあるようにボールCを左手から右側に投げる
    • この辺で上記1で投げたボールAが手元まで落ちてくるので右手でキャッチする
  4. 空中に約3ビートあるようにボールAを右手から左側に投げる
    • この辺で上記2で投げたボールBが手元まで落ちてくるので左手でキャッチする
  5. (以下同様)

という感じで続ける。
特殊な数値として、0、1、2がある。

  • 0:手にボールがない状態を表す
  • 1:片方の手からもう一方の手にボールを渡す動作を表す
  • 2:手にボールを持ったまま投げない状態を表す

どんな数列でもサイトスワップとしてジャグリングできるわけではなく、ジャグリング可能な数列とそうでない数列があって、この判定は数学的にできる。ジャグリング可能な数列からは、その数列で投げるときに必要なボールの数を求めることができる。


さて、サイトスワップを可聴化する意義については本来最も大切なことだけど最後に回して、今回の可聴化のデザインについて書く。可聴化のデザインは単純で、ビートごとに次のルールで音を鳴らす。

  • 数値ひとつを音高に変換(例外的に、0と2のときは音を鳴らさない)
  • ボールを投げる手の左右を音源の位置に変換(ステレオ音にする)
  • 投げたボールをキャッチするまでの時間(ボールの滞空時間)を音価に変換


ChucKのプログラム。コマンドライン引数で可聴化したいサイトスワップを指定して実行する。サイトスワップの数値の分解がChucK側で綺麗にできないので手動でやってもらう仕様にした。例えば「441」というサイトスワップは「4:4:1」のように数値ごとにコロンで区切って指定する必要がある。

me.args() => int N;
minute / 160 => dur BEAT;
[0, 0, 2, 4, 7, 9, 12, 14, 16, 19] @=> int scale[];
60 => int base;
-1 => int init_hand;

Pan2 g => dac;
.1 => g.gain;

// ジャグリング可能なら必要なボールの数を、そうでないなら-1を返す
fun int getBalls() {
    int v, sum, mod;
    int mods[N];
    if (N < 1) return -1;
    for (int i; i < N; i++) {
        me.arg(i) => Std.atoi => v;
        v +=> sum;
        (v + i) % N => mod;
        if (mods[mod]) {
            return -1;
        } else {
            true => mods[mod];
        }
    }
    return sum / N;
}

// 数値v、投げる手handのときのボールの投げ方を可聴化
fun void throw(int v, int hand) {
    Wurley w => Pan2 p => g;
    base + scale[v] => Std.mtof => w.freq;
    hand => p.pan;

    if (v == 0 || v == 2) {
        BEAT => now;
    } else if (v == 1) {
        1 => w.noteOn;
        BEAT => now;
        1 => w.noteOff;
    } else {
        1 => w.noteOn;
        // ボールの滞空時間を音価にする
        // 計算式は下のサイトから持ってきた 
        // http://www.juggling.org/help/siteswap/ssintro/#technotes1
        .7 => float dwell;
        (v - 2 * dwell)::BEAT => now;
        1 => w.noteOff;
    }
}

fun void main() {
    getBalls() => int balls;
    if (balls < 0) {
        <<<"ERROR: not jugglable", "">>>;
        me.exit();
    } else {
        <<<"# of balls: ", balls>>>;
    }
    init_hand => int hand;
    
    for (int i, v; ; (i + 1) % N => i) {
        me.arg(i) => Std.atoi => v;
        spork ~ throw(v, hand);
        BEAT => now;
        -hand => hand;
    }
}

main();

ステレオ音のミックスについてメモ。上のプログラムではsporkされた各Shredが生成した音を出力前にまとめるためにPan2を使っている。これがPan2ではなくGainだとモノラル音でまとめられてしまう。ChucKの公式マニュアルから該当部分を引用。

You can also mix down your stereo signal to a mono signal using the Mix2 object.

adc => Mix2 m => dac.left;

If you remove the Mix2 in the chain and replace it with a Gain object it will act the same way. When you connect a stereo object to a mono object it will sum the inputs.


録音したもの。いくつかのパターンについてひとまとめにした。サイトスワップは順に「3」、「441」、「40」、「1234567」、「50505」。
Download


ここからは、ジャグリングに関して可聴化する意義について書いてみる。自分はジャグリングをやっていないのであくまで想像で。

まずサイトスワップに限らずジャグリング一般について。可聴化について調べたエントリで書いたように、可聴化が活きるケースのひとつに、何かの作業中に視覚が既に使われている状況で補完的な情報を提供する手段として使うというのがある。ジャグリングでは、視覚は使われるし手は完全に塞がってしまうし、他の身体の部位もジャグリングしながら情報を知覚するためにフリーに使えるところはほとんどないだろう。でも(BGMを流してないなら)聴覚はフリーだ。そしてジャグリングの最中にボールを投げる高さやタイミングを知らせる手段として音は有用ではないだろうか。というわけで、今回の可聴化のデザインの良し悪しは別にして、可聴化の適用対象としてはジャグリングは悪くない題材だと思われる。

それと純粋な可聴化からは外れるが、パフォーマンスを意図してジャグリングする場合、サウンドアートとしてBGMとは違う音の要素をジャグリングに付加するということも考えられる。複数人で並行してやっても楽しくなるようにできるかもしれなくもない(全く根拠なしの思い付き)。ざっと探した限りでは、可聴化とサウンドアートの両者を意図した先行研究にJuggling Soundsというのがあった。これはインタラクティブなシステムで、複数のカメラを使って実際のクラブの投げられ方をリアルタイムに解析して対応する音を鳴らすという内容になっている。

最後に今回の可聴化の実現性について結論のないメモを少し。ChucKのプログラムは良く言ってもプロトタイピングしてみましたというレベルだろうけど、実際にこれを実用的なレベルにできるかというと…。少なくともジャグリングの邪魔をせずステレオ音を知覚させる必要があるし、サイトスワップの入力やビートの変更の煩わしさもできるだけ除かないといけない。