   (concat (make-temp-name
 	   (expand-file-name "emacs-eci" temporary-file-directory))
 	  suffix))
+
+(defun ecasound-read-from-minibuffer (prompt default)
+  (let ((result (read-from-minibuffer
+		 (format "%s (default %S): " prompt default)
+		 nil nil nil nil default)))
+    (if (and result (not (string= result "")))
+	result
+      default)))
+
+(defconst ecasound-signalview-clipped-threshold (- 1.0 (/ 1.0 16384)))
+
+(defconst ecasound-signalview-bar-length 55)
+
+(defun ecasound-signalview (bufsize format input output)
+  (interactive
+   (list
+    (ecasound-read-from-minibuffer "Buffersize" "128")
+    (ecasound-read-from-minibuffer "Format" "s16_le,2,44100,i")
+    (let ((file (read-file-name "Input: ")))
+      (if (file-exists-p file)
+	  (expand-file-name file)
+	file))
+    (ecasound-read-from-minibuffer "Output" "null")))
+  (let* ((eci-parse-cleanup-buffer nil)
+	 (handle (eci-init))
+	 (channels (string-to-number (nth 1 (split-string format ","))))
+	 (chinfo (make-vector channels nil)))
+    (dotimes (ch channels) (aset chinfo ch (cons 0 0)))
+    (eci-cs-add "signalview" handle)
+    (eci-c-add "analysis" handle)
+    (eci-cs-set-audio-format format handle)
+    (eci-ai-add input handle)
+    (eci-ao-add output handle)
+    (eci-cop-add "-evp" handle)
+    (eci-cop-add "-ev" handle)
+    (set-buffer (get-buffer-create "*Ecasound-signalview*"))
+    (erase-buffer)
+    (dotimes (ch channels)
+      (insert "---\n"))
+    (setq header-line-format
+	 (list (concat "Channel#"
+		       (make-string (- ecasound-signalview-bar-length 3) 32)
+		       "| max-value  clipped")))
+    (set (make-variable-buffer-local 'ecasignalview-position) "unknown")
+    (set (make-variable-buffer-local 'ecasignalview-engine-status) "unknown")
+    (setq mode-line-format
+	  (list
+	   (list
+	    (- ecasound-signalview-bar-length 3)
+	    (format "Input: %s, output: %s" input output)
+	    'ecasignalview-engine-status)
+	   " | " 'ecasignalview-position))
+    (switch-to-buffer-other-window (current-buffer))
+    (eci-cs-connect handle)
+    (eci-start handle)
+    (sit-for 0.8)
+    (eci-cop-select 1 handle)
+    (while (string= (setq ecasignalview-engine-status
+			  (eci-engine-status handle)) "running")
+      (let ((inhibit-quit t) (inhibit-redisplay t))
+	(setq ecasignalview-position
+	      (let ((secs (eci-cs-get-position handle)))
+		(format "%02d:%02d.%02d"
+			(/ secs 60)
+			(% (round (floor secs)) 60)
+			(* (- secs (floor secs)) 100))))
+	(delete-region (point-min) (point-max))
+	(dotimes (ch channels)
+	  (insert (format "ch%d: " (1+ ch)))
+	  (let ((val (progn (eci-copp-select (1+ ch) handle)
+			    (eci-copp-get handle)))
+		(bl ecasound-signalview-bar-length))
+	    (insert
+	     (concat
+	      (make-string (round (* val bl)) ?*)
+	      (make-string (- bl (round (* val bl))) ? )))
+	    (if (> val (car (aref chinfo ch)))
+		(setcar (aref chinfo ch) val))
+	    (if (> val ecasound-signalview-clipped-threshold)
+	      (incf (cdr (aref chinfo ch))))
+	    (insert (format "| %.4f     %d\n" (car (aref chinfo ch))
+			    (cdr (aref chinfo ch))))))
+	(goto-char (point-min)))
+      (sit-for 0.1)
+      (fit-window-to-buffer))
+    (goto-char (point-max))
+    (let ((pos (point)))
+      (insert
+       (nth 2
+	    (nth 2
+		 (nthcdr 2
+			 (assoc "Volume analysis"
+				(assoc "analysis"
+				       (eci-cop-status handle)))))))
+      (goto-char pos))
+    (recenter channels)
+    (fit-window-to-buffer)))
 
 (defun ecasound-normalize (filename)
   "Normalize a audio file using ECI."

	(when result
	  (setq eci-result
		(cond
		 ((string= eci-last-command "cop-register")
		  (eci-process-cop-register result))
		 ((string= eci-last-command "cop-status")
		  (eci-process-cop-status result))
		 ((string= eci-last-command "preset-register")
		  (eci-process-preset-register result))
		 ((string= eci-last-command "ctrl-register")
		  (eci-process-ctrl-register result))
		 ((string= eci-last-command "ladspa-register")
		  (eci-process-ladspa-register result))
		 ((string= eci-last-command "int-output-mode-wellformed")
		  (if (eq result t)
		      (setq eci-int-output-mode-wellformed-flag t)))
		 (t
		  (if (and (listp result)
			   (eq (nth 0 result) 'error))
		      nil
		    result)))))))))

;;; Ecasound-iam-mode pcomplete functions


				(string-to-number (match-string 3 elt)))))
		      (split-string
		       (match-string-no-properties 3) ", "))))
		(if (looking-at "\tStatus info:\n")
		    (setq args
			  (append
			   args
			   (list
			    (list
			     "Status info" nil
			     (buffer-substring
			      (progn (forward-line 1) (point))
			      (or (re-search-forward "\n\n" nil t)
				  (point-max))))))))
		(setq chain (cons (append (list name n) args) chain))))
	    (setq result (cons (reverse (append chain (list c))) result))))
	result))))

(defun eci-process-map-list (string)
  "Parse the output of a map-xxx-list ECI command and return an alist.
STRING is the string returned by a map-xxx-list command."
  (mapcar
   (lambda (elt)
     (append
      (list (nth 1 elt) (nth 0 elt) (nth 2 elt))
      (let (res (count (string-to-number (nth 3 elt))))
	(setq elt (nthcdr 4 elt))
	(while (> count 0)
	  (setq
	   res
	   (cons
	    (list (nth 0 elt) (nth 1 elt)
		  (string-to-number (nth 2 elt)) ;; default value
		  (when (string= (nth 3 elt) "1")
		    (string-to-number (nth 4 elt)))
		  (when (string= (nth 5 elt) "1")
		    (string-to-number (nth 6 elt)))
		  (cond
		   ((string= (nth 7 elt) "1")
		    'toggle)
		   ((string= (nth 8 elt) "1")
		    'integer)
		   ((string= (nth 9 elt) "1")
		    'logarithmic)
		   ((string= (nth 10 elt) "1")
		    'output))) res)
	   elt (nthcdr 11 elt)
	   count (1- count)))
	(reverse res))))
   (mapcar (lambda (str) (split-string str ","))
	   (split-string string "\n"))))

(defeci cs-set-audio-format
  ((format (ecasound-read-from-minibuffer
	    "Audio format" "s16_le,2,44100,i") "%s")))

(defeci cop-register)
(defeci preset-register)
(defeci ctrl-register)

(defeci cop-status ()
  ""
  (let ((eci-hide-output (not (interactive-p))))
    (eci-command "cop-status" buffer-or-process)))

(defeci ladspa-register "" nil
  (let ((eci-hide-output (not (interactive-p))))
    (eci-command "ladspa-register")))

(defun ecasound-read-copp (copp)
  "Interactively read one chainop parameter."
  (let* ((completion-ignore-case t)
	 (default (format "%S" (nth 2 copp)))
	 (answer
	  (read-from-minibuffer
	   (concat
	    (car copp)
	    " (default " default "): ")
	   nil nil nil nil
	   default)))
    (if (and answer (not (string= answer "")))
	answer
      default)))

(defun ecasound-cop-add ()
  "Interactively prompt for the name and argument of a chain operator to add."
  (interactive)
  (unless eci-map-cop-list
    (eci-map-cop-list))
  (unless eci-map-ladspa-list
    (eci-map-ladspa-list))
  (unless eci-map-preset-list
    (eci-map-preset-list))
  (let* ((cop (completing-read "Chain operator: "
			       (append eci-map-cop-list eci-ladspa-register
				       eci-map-preset-list)))
	 (arg (nth 1 (or (assoc cop eci-map-cop-list)
			 (assoc cop eci-map-ladspa-list)
			 (assoc cop eci-map-preset-list)))))
    (eci-cop-add
     (concat
      (cond
       ((assoc cop eci-map-cop-list)
	(concat "-" arg ":"))
       ((assoc cop eci-map-ladspa-list)
	(concat "-el:" arg ","))
       ((assoc cop eci-map-preset-list)
	(concat "-pn:" arg ",")))
      (mapconcat #'ecasound-read-copp
		 (or (nthcdr 3 (assoc cop eci-map-cop-list))
		     (nthcdr 3 (assoc cop eci-map-ladspa-list))
		     (nthcdr 3 (assoc cop eci-map-preset-list))) ",")))))

(defun ecasound-ctrl-add ()
  "Prompt for the name and arguments of a chainop controllerr to add."
  (interactive)
  (unless eci-map-ctrl-list
    (eci-map-ctrl-list))
  (let ((ctrl (completing-read "Chain operator controller: "
			       eci-map-ctrl-list)))
    (eci-ctrl-add
     (concat
      "-" (nth 1 (assoc ctrl eci-map-ctrl-list)) ":"
      (mapconcat
       #'ecasound-read-copp
       (nthcdr 3 (assoc ctrl eci-map-ctrl-list))
       ",")))))

;;; ChainOp Editor
