2010-05-02
2010-02-07
emacs設定をまとめる
家のメインPC、メインサーバ、会社のPC、Lisp専用機、そしてNetWalker。
其々でemacsを使っているので、設定をまとめました。
といっても前からsvnで管理していたのでほとんどそういう風にはなってたのですが、直接X上で起動した時とmlterm,screenから起動した時で挙動を変えたいので関数を用意してみました。
(defun on-x? () (getenv "DISPLAY"))
判定がベストとはあんまり思えないけど思うように動いたのでとりあえずおk。
(when (on-x?) (menu-bar-mode nil) (tool-bar-mode nil) (scroll-bar-mode nil))
こんな感じの使い方。
ちなみに家のPCはWindowsXPのMeadowもありますが面倒臭すぎて無視。Win上で開発しないしサクラエディタでいいや。
2010-01-30
コード進行とCLを同時に勉強してみた その3
調子に乗ってダイアトニックコードを表示するプログラムを作ってみました。
お陰でCLも学べるしコード進行も少しずつ理解出来てきてるしで超絶一石二鳥です。
(defvar *major-diatonic-types* '("" "m" "m" "" "" "m" "dim"))
(defvar *major-diatonic-structure* '(0 2 2 1 2 2 2))
(defvar *minor-diatonic-types* '("m" "dim" "" "m" "" "" ""))
(defvar *minor-diatonic-structure* '(0 2 1 2 2 1 2))
(defun diatonic-chord (key)
(let ((types *major-diatonic-types*)
(structure *major-diatonic-structure*))
(when (char= #\m (last-char key))
(setf types *minor-diatonic-types*
structure *minor-diatonic-structure*
key (subseq key 0 (1- (length key)))))
(do ((i 0 (1+ i))
(base (input-note-pos key *input-notes*))
(ret ()))
((= i (length types)) (list-to-delimited-string (nreverse ret)))
(push
(concatenate 'string
(get-note (incf base (get-note i structure)) *input-notes*)
(nth i types)) ret))))
(defun |#@-reader| (stream sub-char numarg)
(declare (ignore sub-char numarg))
(let ((data (read-line stream)))
(diatonic-chord data)))
(set-dispatch-macro-character #\# #\@ #'|#@-reader|)
実行。
CHORD-MUSIC> #@C "C Dm Em F G Am Bdim" CHORD-MUSIC> #@Am "Am Bdim C Dm E F G" CHORD-MUSIC> #@C#m "C#m D#dim E F#m G# A B"
use-packageさせる気ないんでリーダマクロ使いまくってます^q^
コード進行とCLを同時に勉強してみた その2
長いので分けました。
本当にやりたかったのはコッチです。
(in-package :com.strnet.chord-music)
(defun read-delimited-string (endchar stream)
(do ((c (read-char stream) (read-char stream))
(ret))
((char= c endchar) (coerce (nreverse ret) 'string))
(push c ret)))
(set-macro-character #\[
#'(lambda (stream char)
(declare (ignore char))
(let ((data (read-delimited-string #\] stream)))
(generate-music data))))
(set-macro-character #\] (get-macro-character #\)))
(defun |#?-reader| (stream sub-char numarg)
(declare (ignore sub-char numarg))
(let ((data (read-line stream)))
(mv-bind (chord type) (chord->chord-type data)
(format nil "~{~a~^ ~}" (get-notes chord type nil)))))
(set-dispatch-macro-character #\# #\? #'|#?-reader|)
これでREPL上で色々遊べるようになりました。
#?<コード> で、そのコードで使われる音が表示。
[コード コード ...] で、*three-pattern* *fourth-pattern*で指定したテンプレ通りに音階が出てきます。
CHORD-MUSIC> #?Am "ラ ド ミ" CHORD-MUSIC> [C F G C] "ドミーソドミッソ ファラー‘ドファラッ‘ド ソシー‘レソシッ‘レ ドミーソドミッソ"
*three-pattern*で '(0 1 ^ 2 0 1 r 2)と指定してるので、
0,1,2 => ド,ミ,ソ
^ => 音を伸ばす(MML表記;)
r => 休符(MML表記;)
なのでドミーソドミッソになります。
threeとfourceはコードの構成が3和音か4和音かの違いです;
[C F G C]
これも立派なLispコードになったので、
CHORD-MUSIC> (print-chords [C F G C] [CM7 Am7 FM7 G7]) "ドミーソドミッソ ファラー‘ドファラッ‘ド ソシー‘レソシッ‘レ ドミーソドミッソ ドミソシドミソシ ラ‘ド‘ミ‘ソラ‘ド‘ミ‘ソ ファラ‘ド‘ミファラ‘ド‘ミ ソシ‘レ‘ファソシ‘レ‘ファ"
そのまま関数に渡せたりします。
誰得。
ちなみに上記のはストトン表記というやつで、MML表記の場合はこうなります。
CHORD-MUSIC> (mml-mode)
#S(NOTATION
:NOTES ("c" "c#" "d" "d#" "e" "f" "f#" "g" "g#" "a" "a#" "b")
:OCTAVES ("\"" "" "`")
:REST-CHAR #\r
:STRETCH-CHAR #\^)
CHORD-MUSIC> #?Esus4
"e a b"
CHORD-MUSIC> [C F G C]
"ce^gcerg fa^`cfar`c gb^`dgbr`d ce^gcerg"
コード進行とCLを同時に勉強してみた その1
ふと思いついたので作ってみました。
勉強用なので完璧に作ろうとはしてません←言い訳
パッケージ作りから。
(defpackage :com.strnet.chord-music (:use :cl :kmrcl :com.strnet.util :split-sequence))
com.strnet.utilの中身のほとんどはkmrclに入ってない、"On Lisp" "LET OVER LAMBDA" の中で出てくる有用そうなコードが詰まってます。
以下一気にプログラム。
(in-package :com.strnet.chord-music)
(defvar *input-notes* '("C" "C#" "D" "D#" "E" "F" "F#" "G" "G#" "A" "A#" "B"))
(defparameter *chord-structure* (make-hash-table :test 'equal))
(defparameter *notation* nil)
(defstruct notation
notes octaves rest-char stretch-char)
(defun roll-index (i place)
(truncate i (length place)))
(defun get-note (i place)
(case i
(r (notation-rest-char *notation*))
(^ (notation-stretch-char *notation*))
(t (mv-bind (mod index) (roll-index i place)
(declare (ignore mod))
(nth index place)))))
(defun add-chord-type (type &rest struct)
(setf (gethash type *chord-structure*) struct))
(defun deco-octave (x note)
(concatenate 'string
(nth (nif x 2 1 0) (notation-octaves *notation*))
note))
(defun input-note-pos (chord &optional (notes *input-notes*))
(aif (position chord notes :test 'equalp)
it
(error "Unknown chord [~a]" chord)))
(defun get-structure (type)
(aif (gethash type *chord-structure*)
it
(error "Unknown type [~a]" type)))
(defun get-notes (chord type &optional (decolate t))
(let ( (pos (input-note-pos chord))
(struct (get-structure type)))
(flet ((get-node (x)
(mv-bind (mod index) (roll-index (incf pos x) (notation-notes *notation*))
(if decolate
(deco-octave mod (nth index (notation-notes *notation*)))
(nth index (notation-notes *notation*))))))
(mapcar #'get-node struct))))
(defparameter *three-pattern* '(0 1 ^ 2 0 1 r 2))
(defparameter *four-pattern* '(0 1 2 3 0 1 2 3))
(defun tone-pattern (notes)
(case (length notes)
(3 *three-pattern*)
(4 *four-pattern*)))
(defun generate-notes (chord type)
(let ((notes (get-notes chord type)))
(mapcar #'(lambda (x)
(get-note x notes)) (tone-pattern notes))))
上記をベースに色々と定義
(defun mml-mode ()
(setf *notation*
(make-notation
:notes '("c" "c#" "d" "d#" "e" "f" "f#" "g" "g#" "a" "a#" "b")
:octaves '("\"" "" "`")
:rest-char #\r
:stretch-char #\^)))
(defun sttn-mode ()
(setf *notation*
(make-notation
:notes '("ド" "ド#" "レ" "レ#" "ミ" "ファ" "ファ#" "ソ" "ソ#" "ラ" "ラ#" "シ")
:octaves '("”" "" "‘")
:rest-char #\ッ
:stretch-char #\ー)))
(add-chord-type "" 0 4 3)
(add-chord-type "m" 0 3 4)
(add-chord-type "7" 0 4 3 3)
(add-chord-type "M7" 0 4 3 4)
(add-chord-type "m7" 0 3 4 3)
(add-chord-type "sus4" 0 5 2)
(add-chord-type "add9" 0 4 3 7)
(add-chord-type "madd9" 0 3 4 7)
(add-chord-type "aug" 0 4 4)
(add-chord-type "dim" 0 3 3)
(add-chord-type "m7-5" 0 3 3 4)
(sttn-mode)
というわけで、コードを入れると"ドミソ"みたいに展開される感じのプログラムです。
こんな感じになります。
CHORD-MUSIC> (generate-music "C Dm") "ドミーソドミッソ レファーラレファッラ"
2010-01-22
kmrcl凄いlol
kmrcl:comcat-symbol-pkgこそ昨日望んでた関数でした。
そういえばLET OVER LAMBDA読み終わりました。
On Lisp同様後半はサラッと読んだ程度ですが;
少しでも血肉になればもうけもん。
2010-01-19
独習LET OVER LAMBDA
第5章のalet辺りからきついです。
電車内で読んでるだけだとマクロが脳内展開できない;
macroでどのくらいまで無茶やっていいのか自信を付けてくれる本かなというのが現時点の感想。

Emacs が X 上で動作しているか、ターミナル上で動作しているかの判別方法ですが、
window-system 変数を使用してみてはいかがでしょうか。こんな感じです。
#Emacs 23.1.92 on Ubuntu, Meadow3 on Windows で確認。
(when (on-x?)
↓
(when window-system
window-system、イケそうです!ありがとうございます^q^