bonar note

京都のエンジニア bonar の技術的なことや技術的でない日常のブログです。

Music::AutoPhrase - code-base music composition library

Music::AutoPhrase というモジュールを coderepos に上げました。以下のコマンドでチェックアウトできます。

svn checkout http://svn.coderepos.org/share/lang/perl/Music-AutoPhrase

まだ完成度が低くて、「なんとか動く」っていうレベルではありますが。。

以前 Music::Phrase::MMLGenerator というモジュールを上げていて、基本的なコンセプトそれと同じです。音楽的な教養の無い僕のような人が簡単に音楽を作成できるように、ベースとなるコード進行と音がなるタイミングだけを指示すれば音楽が(いまのところはMIDIファイルが)出きるような仕組みになっています。以前のモジュールから以下のような改善を行っています。

  • 全体的にクラス構造を見直してコードを書き直した
    • 実際に音をどう選択するかのアルゴリズムを後から追加できるようにした
  • pmml という外部アプリケーションへの依存を無くした(MIDI::SImpleに移行)
  • マルチトラックに対応

特定のコマンドラインスクリプトにオプションを与えてファイルを生成するスタイルから、perlスクリプトそのものが1つの楽曲になるような感じに方向転換しています。具体的には以下のようなコードになります。

demo/sample2.pl

#!/usr/bin/perl

use strict;
use warnings;

use Music::AutoPhrase;

my $track = new_track();
$track->set_tempo(120);
$track->set_base_code(qw/
    F G E A
    F G E A
/);
my (@channel);
$channel[0] = new_channel(
    inst  => 2,
    vol   => 60,
    octav => [qw/4 5/],
)->push(
    '2-------2-------2-------2-------',
    '2-------2-------2-------2-------',
);

$channel[1] = new_channel(
    inst     => 69,
    vol      => 90,
    octav    => [qw/5 6/],
    selector => 'Loose',
)->push(
    '111-1-11-1-11-1-111-1-11-11-1-1-',
    '111-1-11-1-11-1-111-1-11-11-1-1-',
);

$track->push_channel(@channel);
save_as_midi($track, $0 . '.mid');

このplを実行するとMIDIファイルが作成されます。

$track が Music::AutoPhrase::Track オブジェクトで、1つの楽曲を表現しています。new_channel() で Music::AutoPhrase::Channel オブジェクトを作成し、それを$trackにpushしてくことで曲が出来る、っていうのが全体像です。

各チャンネルにpushされている32文字の文字列は Music::AutoPhrase::BeatPattern オブジェクトに変換されて保持されます。これはどういうタイミングで音がなるかを表していて、1なら単音、3なら3和音を $track に設定された base_code にしたがって選び出します。

このコードにしたがって音を選び出す仕組みが Music::AutoPhrase::NoteSelector::* に入っていて、channelオブジェクトのselectorアクセサにセットされたインスタンスが使用されます。デフォルトは Music::AutoPhrase::NoteSelector::Simple で、単純にそのコードを構成する和音の中からランダムに指定された個数の音を選び出します。

package Music::AutoPhrase::NoteSelector::Simple;

use strict;
use warnings;

use Music::AutoPhrase::Note qw/note_uniq/;

use base 'Music::AutoPhrase::NoteSelector';
use List::Util qw/shuffle/;

sub select_note {
    my ($self, $code, $octav_range, $dur, $count) = @_;

    my (@notes);
    for (1..$count) {
        push @notes, Music::AutoPhrase::Note->new(
            octav    => (shuffle @{$octav_range})[0],
            note_num => (shuffle @{$code->candidate()})[0],
            duration => $dur,
        );
    }
    return note_uniq(@notes);
}

$channel[1] で指定しているLoose(Music::AutoPhrase::NoteSelector::Loose)は、そのコードを構成する和音の各音を7度ずらした音を選択時の候補に入れる、というモジュールでこうするとなぜか旋律が不安定で且つ外れすぎない感じになります。

ざっくりとはこんな感じです。かなり作りかけなのでいけてないところが沢山あるのですが、興味のある方はぜひ改善をcommitしていただければと思います。今後は以下の点をもうちょっと改善していきたいなとおもっています。

  • 対応していないMIDI命令への対応
    • 左右のパン
  • DSLチックな書き方が出きるように
  • リズムパートをどうするか考える

まだこれだけではあまり本格的な音楽は作れないかもですが、これで生成したMIDIファイルをGarageBandを組み合わせて編集してeffectをかけたりすると結構おもしろいかなと思っています。
#しかし家のmacbookが死んでGarageBnadが使えない。。。