ならば

音とかで遊んでいたログ

brainChucK

名前から思いついたというか、名前だけ思いついたけど後は特に思いつけなかった。brainfuckを元にしてChucKで音を鳴らす。

ChucKの制約のために変更した仕様

  • brainfuckコードの扱い
    ChucKでは文字列操作がほとんどできないので、brainfuckの8種類の命令><+-.,[]はそれぞれ命令01234567に変換して、各命令をint型配列の要素へ直接格納することにした
  • メモリ領域の要素の型
    ChucKにはbyte型が用意されていないので、int型で代替した

音を扱うために変更した仕様

  • データの扱い
    メモリ領域の各要素にある数値は音高(MIDIノート番号)とみなす
  • 命令4(.)のときの出力方法
    ポインタの指している要素にある音高の音を1秒間鳴らす
  • 命令5(,)のときの入力方法
    PCのキーボードの代わりにMIDIキーボードで音高を入力する


ChucKのプログラム。各種数値の範囲チェックなし。ここではbrainfuckコードとして、Hello worldを変換して使った。

second => dur T;

MidiIn min;
MidiMsg msg;
if ( !min.open(0) ) me.exit();

SinOsc s => ADSR e => dac;
.1 => s.gain;
e.set(ms, .1::T, .3, .2::T);
1 => e.keyOff;

[   // ここに変換したbrainfuckコードを格納する
    // Hello, world!
    2, 2, 2, 2, 2, 2, 2, 2, 2, 
    6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 
    0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
    0, 2, 2, 2, 2, 2, 1, 1, 1, 3, 7, 
    0, 4, 0, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, // Hel
    4, 2, 2, 2, 4, 0, 3, 4,                   // lo,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,    //  
    1, 2, 2, 2, 2, 2, 2, 2, 2, 4,             // w
    3, 3, 3, 3, 3, 3, 3, 3, 4, 2, 2, 2, 4,    // or
    3, 3, 3, 3, 3, 3, 4,                      // l
    3, 3, 3, 3, 3, 3, 3, 3, 4, 0, 2, 4        // d!
] @=> int code[];
int memory[1000];
int pointer;

for (int ip; ip < code.cap(); ip++) {
    if (code[ip] == 0) {        // >
        1 +=> pointer;
    } else if (code[ip] == 1) { // <
        1 -=> pointer;
    } else if (code[ip] == 2) { // +
        1 +=> memory[pointer];
    } else if (code[ip] == 3) { // -
        1 -=> memory[pointer];
    } else if (code[ip] == 4) { // .
        memory[pointer] => Std.mtof => s.freq;
        1 => e.keyOn;
        .8::T => now;
        1 => e.keyOff;
        .2::T => now;
    } else if (code[ip] == 5) { // ,
        int isIn;
        min => now;
        while (min.recv(msg)) {
            // ノートオンかつベロシティが0以外のとき
            if (msg.data1 == 144 && msg.data3) {
                // ポインタの指している要素に音高を格納
                msg.data2 => memory[pointer];
                true => isIn;
                break;
            }
        }
        if (!isIn) 1 -=> ip;
    } else if (code[ip] == 6) { // [
        if (memory[pointer] == 0) {
            1 => int depth;
            while (depth != 0) {
                1 +=> ip;
                if (code[ip] == 6) 1 +=> depth;
                else if (code[ip] == 7) 1 -=> depth;
            }
        }
    } else if (code[ip] == 7) {  // ]
        if (memory[pointer] != 0) {
            1 => int depth;
            while (depth != 0) {
                1 -=> ip;
                if (code[ip] == 6) 1 -=> depth;
                else if (code[ip] == 7) 1 +=> depth;
            }
            1 -=> ip;
        }
    }
}


録音したもの。
Download


初めてMIDIイベントを扱ったが、MIDIメッセージの構成って思っていたより分かりにくい。