Haskore

なんとなく、template Haskellに興味が沸いたりしてDSL Implementation in MetaOCaml, Template Haskell, and C++ などを眺めていたら、examples of Embedding DSLとして、Haskoreというのがあがっていたのだった。
サイト
http://www.haskell.org/haskore/
論文。
http://citeseer.ist.psu.edu/hudak95haskore.html


でもTemplate Haskellは使ってないし(これできた当時はなかったんでないだろうか)、DSLと言っていいのかどうかよくわからんが。Haskoreのサイトや論文には、Computer Music Systemとだけ書いてあって、DSLとは言ってないっぽい。ライブラリとDSLの境はどこだろう

2000年で放置プレイっぽいけど、微修正で、GHC-6.4.2でも動かすことが出来た。
修正内容
・Bitops.hsでfromIntを使ってるけど、今はfromIntってないっぽい?だもんで、fromIntger.toIntegerに置き換える
・IOExtensions.hsも適当に修正
あと一応、Makefileが付いてるけど、Cabal書いた方がいいんでないかな。よく分からんけど。


面白くもなんともない使用例

import Haskore

type PitchFun = Octave -> Dur -> [NoteAttribute] -> Music
mkMusic instr tempo oct ls
 = Instr instr (Tempo tempo (line $ map (\x -> (fst x) oct (snd x) []) ls))

transpf :: Int -> PitchFun -> PitchFun
transpf n f =  mkPitchFun (transPitchClass n (getBase f))
   where
    transPitchClass n ls = map (trans1 n) ls
    trans1 n p = pitch $ n + (pitchClass $ fst p) + 12*(snd p)
    mkPitchFun [(c,oct')] = (\oct -> Note (c,oct+oct'))
    mkPitchFun ((c,oct'):ls) = 
      (\oct dur attr -> (Note (c,oct+oct') dur attr) :=: (mkPitchFun ls oct dur attr))
    getBase p = aux $ p 0 1 []
      where
       aux m = case m of
         Note (c,o) _ _ -> [(c,o)]
         Note (c,o) _ _ :=: m' -> (c,o):(aux m')

majChord root = chords [root,transpf 4 root,transpf 7 root]
minChord root = chords [root,transpf 3 root,transpf 7 root]

chords :: [PitchFun] -> PitchFun
chords [c] = c
chords (c:ls) = (\oct dur attr -> (c oct dur attr) :=: (chords ls oct dur attr))

toMidi m name = do outputMidiFile name $ makeMidi (m,defCon,defUpm)

--こっからメイン
partm = [(g,1/8),(e,1/8),(e,1/4),(f,1/8),(d,1/8),(d,1/4),
         (c,1/8),(e,1/8),(g,1/8),(g,1/8),(e,1/8),(e,1/8),(e,1/4)]

part1 = [(g,1/8),(e,1/8),(e,1/4),(f,1/8),(d,1/8),(d,1/4),(c,1/8),
         (d,1/8),(e,1/8),(f,1/8),(g,1/8),(g,1/8),(g,1/4)]

part2 = [(d,1/8),(d,1/8),(d,1/8),(d,1/8),(d,1/8),(e,1/8),(f,1/4),
         (e,1/8),(e,1/8),(e,1/8),(e,1/8),(e,1/8),(f,1/8),(g,1/4)]

m = mkMusic "piano" 1 4 
     (map (\x-> (majChord $ fst x , snd x)) (part1++partm++part2++partm))

main = toMidi m "pnya.mid"

アルゴリズム作曲とかよくわからんので、適当にロジスティック写像で数列作って、音散らしてみたけど、あんまり面白くなかった。むずいね。まあ、これ使ってMMLコンパイラとか割と楽に作れそうな気がする。Haskore自体がやってることも、Haskellが分かる人なら簡単に理解できる程度だと思う。そして、MMLと比べて、何が新しいのかよく分からなかった


感想。MMLよりは随分敷居が高そうというか、生のHaskoreを、プログラムとか興味もない作曲家が使おうとしたら、きっと挫折するだろうな〜。という意味で、やっぱりDSLというよりはライブラリという気がする。けど、Maximaだって、translator挟んで、生のLispを見えなくしてるだけなので、あんま大差ないのかなぁ