1 ;; $RCSfile: lyqi-midi.el,v $
3 ;; $Date: 2004/03/14 15:16:05 $
6 ;;; Part of lyqi, a major emacs mode derived from LilyPond-Mode,
7 ;;; for quick note insertion while editing GNU LilyPond music scores.
9 ;;; (c) copyright 2003 Nicolas Sceaux <nicolas.sceaux@free.fr>
10 ;;; See http://nicolas.sceaux.free.fr/lilypond/
16 (defcustom lyqi-midi-demon-command "timidity -iA -B2,8 -Os -EFreverb=0"
17 "Command used to start the midi demon."
21 (defcustom lyqi-midi-keyboard-command "mymidikbd"
22 "Command used to start the midi keyboard process."
26 (defcustom lyqi-midi-enabled-default nil
27 "Automatically launch midi?"
31 (defcustom lyqi-midi-external-timidity-port 128
32 "ALSA port of external timidity server."
36 (defcustom lyqi-midi-use-external-timidity-server nil
37 "If true, don't start a new timidity server, but use an existing
38 one, which port is `lyqi-midi-external-timidity-port'."
42 (defvar lyqi-midi-tempo 80
43 "Tempo used for play back (quaters per minute).")
45 (defvar lyqi-midi-manually-off nil
46 "Tells if user has previously switched off midi")
48 (defvar lyqi-midi-timidity nil
49 "The timidity demon process.")
51 (defvar lyqi-midi-keyboard nil
52 "The midi keyboard process.")
54 (defvar lyqi-midi-on nil
55 "Say if midi processes are running")
57 (defun lyqi-midi-set-timidity-alsa-port (port)
58 "When using an external timidity demon, set its ALSA sequencer port."
59 (interactive "nTimidity ALSA port: ")
60 (setf lyqi-midi-external-timidity-port port)
61 (when lyqi-midi-timidity
62 (setf (slot-value lyqi-midi-timidity 'seqport) port)))
64 (defun lyqi-midi-timidity-start ()
65 (process-start lyqi-midi-timidity)
66 (mapcar (lambda (client)
67 (setf (slot-value client 'server-port)
68 (slot-value lyqi-midi-timidity 'seqport)))
69 (list lyqi-midi-keyboard)))
70 ;;(list lyqi-midi-keyboard lyqi-midi-rumor)))
72 (defun lyqi-midi-start ()
73 "Starts the timidity process with ALSA interface
74 and the keyboard process."
76 (lyqi-midi-timidity-start)
77 (process-start lyqi-midi-keyboard))
78 (setq lyqi-midi-on (and (process-runningp lyqi-midi-timidity)
79 (process-runningp lyqi-midi-keyboard))))
81 (defun lyqi-midi-stop ()
82 "Stops timidity and keyboard processes."
83 (process-stop lyqi-midi-timidity)
84 (process-stop lyqi-midi-keyboard)
85 (setq lyqi-midi-on nil))
87 (defmethod play-note ((note mudela-note) &optional short)
88 "Play the given note, by sending its pitch and length (in sec)
89 to the midi keyboard process."
90 (when (process-runningp lyqi-midi-keyboard)
91 (with-slots (duration dots) note
93 (process-name (slot-value lyqi-midi-keyboard 'process))
98 (* (expt 2.0 (- 3 duration))
100 (sum 0.0 (+ sum (expt 2.0 (- i)))))
102 (/ 60.0 (* 1.0 lyqi-midi-tempo)))))))))
104 (defmethod play-note ((word mudela-word-duration) &optional short)
105 "Play the given note, by sending its pitch and length (in sec)
106 to the midi keyboard process."
107 (when (process-runningp lyqi-midi-keyboard)
108 (with-slots (duration dots) word
109 (process-send-string (process-name (slot-value lyqi-midi-keyboard 'process))
112 (* (expt 2.0 (- 3 duration))
114 (sum 0.0 (+ sum (expt 2.0 (- i)))))
116 (/ 60.0 (* 1.0 lyqi-midi-tempo))))))))
118 (defmethod play-note ((word mudela-word) &optional short)
119 "Play the given note, by sending its pitch and length (in sec)
120 to the midi keyboard process."
123 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124 (defclass midi-process ()
125 ((command :initarg :command
127 :documentation "process start command")
130 :documentation "process command arguments")
133 :documentation "process name")
134 (process :initform nil
135 :documentation "process object")))
136 (defmethod process-runningp ((process midi-process))
137 "Return t if the process is running, nil otherwise."
138 (with-slots ((proc process)) process
139 (and proc (eq (process-status proc) 'run))))
140 (defmethod process-start ((process midi-process))
142 (unless (process-runningp process)
143 (with-slots (name command args) process
144 (setf (slot-value process 'process)
145 (apply 'start-process name name (append (split-string command " ")
147 (defmethod process-stop ((process midi-process))
149 (when (process-runningp process)
150 (with-slots ((proc process)) process
151 (delete-process (process-name proc)))))
153 (defclass timidity-server (midi-process)
154 ((seqport :initform nil
155 :documentation "Timidity ALSA sequencer port")))
156 (defmethod process-start :AFTER ((timidity timidity-server))
157 "Grep the sequencer port."
158 ;; we have to wait a bit before reading timidity's output
161 (with-current-buffer (buffer-name (process-buffer (slot-value timidity 'process)))
162 (goto-char (point-max))
163 (if (re-search-backward "Opening sequencer port: \\([0-9]+\\):" nil t)
164 (buffer-substring (match-beginning 1)
167 (setf (slot-value timidity 'seqport) (string-to-int port)))))
169 (defclass external-timidity-server (midi-process)
170 ((seqport ;:initform lyqi-midi-external-timidity-port
171 :documentation "External timidity ALSA sequencer port")))
172 (defmethod process-runningp ((timidity external-timidity-server))
174 (defmethod process-start ((timidity external-timidity-server))
176 (defmethod process-stop ((timidity external-timidity-server))
180 (defclass timidity-client (midi-process)
181 ((server-port :initform nil
182 :documentation "The timidity server ALSA port")))
184 (defclass mymidikbd (timidity-client) nil)
185 (defmethod process-start :BEFORE ((kbd mymidikbd))
186 "Update command argument list before execution."
187 (setf (slot-value kbd 'args)
188 (list (number-to-string (slot-value kbd 'server-port)))))