前回に続いて、乱数を用いた楽曲制作方法について紹介します。
今回は、複数の楽器のサンプル、シーケンスパターン、エフェクトパラメータを一気に変更し、自動作曲のようなことをやってみます。
以下の順で説明します。
- 1つの楽器のサンプル変更
- 複数の楽器のサンプル一括変更
- 複数の楽器のサンプル、シーケンスパターン、エフェクトパラメータの一括変更
1つの楽器のサンプル変更
まず最初に、1つの楽器のサンプルの変更をやってみます。
サンプル名称のリストを事前に準備し、ランダムに取り出した値を各種楽器に適用する、というアプローチを取ります。
まず、Dirtのサンプルの名称をリスト化しておきます。(全サンプルでも構いません)
sampli = ["bd","cp","hh","sd","bass","arpy","808"]
次に、randomRIO関数で取得した値をインデックスとして、先程作成したリストの中からひとつを選び出し、変数randsamに格納します。
tmp <- randomRIO (0,(length sampli -1)) -- インデックス番号を生成
randsam = sampli !! (fromIntegral tmp) -- リストから取得
d1 $ s "bd" (# s randsam) -- 楽器に適用
これで、d1のサンプルをランダムに変更することができました!!
複数の楽器のサンプル一括変更
次に、同様のアプローチで、複数の楽器のサンプル一括変更を試みます。
楽器ごとの乱数を取得します。
tmp1 <- randomRIO (0,(length sampli -1))
tmp2 <- randomRIO (0,(length sampli -1))
tmp3 <- randomRIO (0,(length sampli -1))
-- 3行同時に実行するとエラーとなる
・・・実は、アクション(<-)は複数行同時実行ができません。
これだと楽器の数だけ実行が必要となり、非常に面倒です。。。
複数行同時実行ができない理由が気になる方は下記を参照してください。
理由:アクションは、ghciという対話環境以外ではdoブロック内でしか複数行同時実行できないという制約があります。TydalCyclesの実行環境はghciという対話環境で実行されており、doブロックを作ることができません。(実はTydalCyclesの記法のdoは、haskellのdoとは別物です。)
そのため今度は、アクションで乱数のシードのみを生成し、
サンプルリストからランダムに抽出した別のリストを生成するというアプローチを取ります。
seed <- randomRIO (0, 1000) -- シード生成
rnumlist = take 10 $ randomRs (1,(length sampli - 1)) (mkStdGen (fromIntegral seed))
randsampli = [sampli !! x | x <- rnumlist]
-- リスト生成 2行同時実行可
randsampli -- ["bass","808","hh","arpy","808","808","bd","sd","hh","arpy"]
作ったリストrandsampliを複数の楽器に適用します。
d1 $ s "bd" (# s randsampli !! 1) -- "808"
d2 $ s "bd" (# s randsampli !! 2) -- "hh"
d3 $ s "bd" (# s randsampli !! 3) -- "arpy"
できました!!
複数の楽器のサンプル、シーケンスパターン、エフェクトパラメータの一括変更
いよいよ最後です。
シーケンスパターン、エフェクトのパラメータにも同様のアプローチを適用してみましょう。
シーケンス
適当に作成したシーケンスパターンを同じくリスト化しておきます。
seqli = ["v*8", "v ~ v ~", "[~ ~v]*2? v v? v*4"]
エフェクト(pan)のパラメータ
今回はpan用に、以下を用意してみます。エフェクトに合わせたリストを作ります。
panli = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
では、、、
seed <- randomRIO (0, 1000)
rnumlist = take 10 $ randomRs (1,(length sampli - 1)) (mkStdGen (fromIntegral seed))
randsampli = [sampli !! x | x <- rnumlist]
rnumlist = take 10 $ randomRs (1,(length seqli - 1)) (mkStdGen (fromIntegral seed))
randseqli = [seqli !! x | x <- rnumlist]
rnumlist = take 10 $ randomRs (1,(length panli - 1)) (mkStdGen (fromIntegral seed))
randseqli = [panli !! x | x <- rnumlist]
d1 $ s (randseqli !! 1) (# s randsampli !! 1) # pan (panli !! 1)
d2 $ s (randseqli !! 2) (# s randsampli !! 2) # pan (panli !! 2)
d3 $ s (randseqli !! 3) (# s randsampli !! 3) # pan (panli !! 3)
できました!!!
これで自動作曲・・・に近づきました・・・?