「マッチ箱の脳」というとっても平易な人工知能の入門書がある。WEBバージョンもある。素晴らしい。

この本には L-system を自動作曲に応用する章がある。そこに載っている一番簡単な自動作曲装置をChucKで実装してみた。

L-systemの仕様としては、初期状態が「ド」で、置換規則が

となっている。この表現では文字とその解釈が一体化しているけれど、本来L-systemそのものは置換規則に従って単に文字列を生成するだけで、文字列を何に応用するか（どう解釈するか）はL-systemとは独立している。



実装では7種類の文字 ドレミファソラシ をそれぞれ 0123456 に変換した。

14 => int N; // 置換規則を適用する回数 .3::second => dur T; StifKarp karp => JCRev rev => dac; .1 => karp.gain; .7 => rev.mix; class Symbol { int symbol; // 文字 null @=> Symbol @ next; } Symbol @ str; // 文字列 init([0]); for (int i; i < N; i++) next(); play(); fun void init(int axiom[]) { new Symbol @=> str; axiom[0] => str.symbol; str @=> Symbol tail; for (1 => int i; i < axiom.cap(); i++) { add(tail, axiom[i]) @=> tail; } } // 置換規則の実装 fun void next() { int s; for (str @=> Symbol @ p; p != null; p.next @=> p) { p.symbol => s; if (s == 0) { 2 => p.symbol; add(add(p, 1), 3) @=> p; } else if (s == 1) { 0 => p.symbol; } else if (s == 2) { // do nothing } else if (s == 3) { 4 => p.symbol; add(p, 6) @=> p; } else if (s == 4) { 1 => p.symbol; add(p, 5) @=> p; } else if (s == 5) { 3 => p.symbol; } else if (s == 6) { // do nothing } } } // 文字列の解釈の実装 fun void play() { [0, 2, 4, 5, 7, 9, 11] @=> int scale[]; for (str @=> Symbol @ p; p != null; p.next @=> p) { 60 + scale[p.symbol] => Std.mtof => karp.freq; 1 => karp.pluck; T => now; } T => now; } fun Symbol add(Symbol pre, int s) { Symbol ns; s => ns.symbol; pre.next @=> ns.next; ns @=> pre.next; return ns; }

StifKarpはSTKのユニットジェネレータで、撥弦楽器の音をシミュレートする。

録音したもの。



自己相似的なメロディ。