299 lines
10 KiB
EmacsLisp
299 lines
10 KiB
EmacsLisp
;;; sclang-server.el --- IDE for working with SuperCollider -*- coding: utf-8;
|
|
;;
|
|
;; Copyright 2003 stefan kersten <steve@k-hornz.de>
|
|
|
|
;;; License:
|
|
|
|
;; This program is free software; you can redistribute it and/or
|
|
;; modify it under the terms of the GNU General Public License as
|
|
;; published by the Free Software Foundation; either version 2 of the
|
|
;; License, or (at your option) any later version.
|
|
;;
|
|
;; This program is distributed in the hope that it will be useful, but
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
;; General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; if not, write to the Free Software
|
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
;; USA
|
|
|
|
|
|
;;; Commentary:
|
|
;; Interface to the sclang server
|
|
|
|
(require 'cl-lib)
|
|
(require 'sclang-util)
|
|
(require 'sclang-interp)
|
|
(require 'sclang-language)
|
|
(require 'sclang-mode)
|
|
|
|
;;; Code:
|
|
|
|
(defcustom sclang-server-panel "Server.default.makeWindow"
|
|
"Expression to execute when `sclang-show-server-panel' is invoked."
|
|
:group 'sclang-interface
|
|
:type '(choice (const "Server.default.makeWindow")
|
|
(const "\\SCUM.asClass.do { \\SCUM.asClass.desktop.showServerPanel }")
|
|
string))
|
|
|
|
(defvar sclang-server-alist nil
|
|
"Alist of currently defined synthesis servers.")
|
|
|
|
(defvar sclang-default-server nil
|
|
"Default synthesis server.")
|
|
|
|
(defvar sclang-current-server nil
|
|
"Currently selected synthesis server.")
|
|
|
|
(defvar sclang-current-server-initialized nil
|
|
"Non nil when the current server has been initialized from the default server.")
|
|
|
|
(defconst sclang-server-running-face
|
|
(let ((face (make-face 'sclang-server-running-face)))
|
|
(set-face-foreground face "red")
|
|
face)
|
|
"Face for highlighting a server's running state in the mode-line.")
|
|
|
|
(defun sclang-get-server (&optional name)
|
|
"Get sclang server (optionally by NAME)."
|
|
(unless name (setq name sclang-current-server))
|
|
(cdr (assq name sclang-server-alist)))
|
|
|
|
(defun sclang-set-server (&optional name)
|
|
"Set current sclang server (optionally by NAME)."
|
|
(unless name (setq name sclang-current-server))
|
|
(setq sclang-current-server
|
|
(car (or (assq name sclang-server-alist)
|
|
(car sclang-server-alist)))))
|
|
|
|
(sclang-set-command-handler
|
|
'_updateServer
|
|
(lambda (arg)
|
|
(setq sclang-server-alist
|
|
(sort (cdr arg) (lambda (a b) (string-lessp (car a) (car b)))))
|
|
(setq sclang-default-server (car arg))
|
|
(unless sclang-current-server-initialized
|
|
;; only set the current server automatically once after startup
|
|
(setq sclang-current-server-initialized t)
|
|
(sclang-set-server sclang-default-server))
|
|
(sclang-update-server-info)))
|
|
|
|
(defun sclang-next-server ()
|
|
"Select next server for display."
|
|
(interactive)
|
|
(sclang-set-server)
|
|
(let ((list (or (cdr (cl-member-if (lambda (assoc)
|
|
(eq (car assoc) sclang-current-server))
|
|
sclang-server-alist))
|
|
sclang-server-alist)))
|
|
(setq sclang-current-server (car (car list))))
|
|
(sclang-update-server-info))
|
|
|
|
(defun sclang-mouse-next-server (_event)
|
|
"Select next server for display."
|
|
(interactive "e")
|
|
(sclang-next-server))
|
|
|
|
(defun sclang-server-running-p (&optional name)
|
|
"Is the sclang server NAME running?"
|
|
(plist-get (sclang-get-server name) 'running))
|
|
|
|
(defun sclang-server-booting-p (&optional name)
|
|
"Is the sclang server NAME running?"
|
|
(plist-get (sclang-get-server name) 'booting))
|
|
|
|
(defun sclang-create-server-menu (title)
|
|
"Create the server menu with TITLE."
|
|
(easy-menu-create-menu
|
|
title
|
|
'(
|
|
["Boot" sclang-server-boot]
|
|
["Quit" sclang-server-quit]
|
|
"-"
|
|
["Free All" sclang-server-free-all :active (sclang-server-running-p)]
|
|
["Make Default" sclang-server-make-default])))
|
|
|
|
(defun sclang-server-fill-mouse-map (map prefix)
|
|
"Fill mouse MAP using PREFIX."
|
|
(define-key map (vector prefix 'mouse-1) 'sclang-mouse-next-server)
|
|
(define-key map (vector prefix 'down-mouse-3) (sclang-create-server-menu "Commands"))
|
|
map)
|
|
|
|
(defvar sclang-server-mouse-map (sclang-server-fill-mouse-map (make-sparse-keymap) 'mode-line)
|
|
"Keymap used for controlling servers in the mode line.")
|
|
|
|
(defun sclang-server-fill-key-map (map)
|
|
"Fill server keymap MAP."
|
|
(define-key map [?b] 'sclang-server-boot)
|
|
(define-key map [?d] 'sclang-server-display-default)
|
|
(define-key map [?f] 'sclang-server-free-all)
|
|
(define-key map [?m] 'sclang-server-make-default)
|
|
(define-key map [?n] 'sclang-next-server)
|
|
(define-key map [?o] 'sclang-server-dump-osc)
|
|
(define-key map [?p] 'sclang-show-server-panel)
|
|
(define-key map [?q] 'sclang-server-quit)
|
|
(cl-flet ((fill-record-map (map)
|
|
(define-key map [?n] 'sclang-server-prepare-for-record)
|
|
(define-key map [?p] 'sclang-server-pause-recording)
|
|
(define-key map [?r] 'sclang-server-record)
|
|
(define-key map [?s] 'sclang-server-stop-recording)
|
|
map))
|
|
(define-key map [?r] (fill-record-map (make-sparse-keymap))))
|
|
map)
|
|
|
|
(defvar sclang-server-key-map (sclang-server-fill-key-map (make-sparse-keymap))
|
|
"Keymap used for controlling servers.")
|
|
|
|
(defun sclang-get-server-info-string ()
|
|
"Return a mode-line string for the current server."
|
|
(let* ((name (if sclang-current-server (symbol-name sclang-current-server) "-------"))
|
|
(server (sclang-get-server))
|
|
(running-p (if server (plist-get server 'running)))
|
|
(string (propertize
|
|
name
|
|
'face (if running-p sclang-server-running-face)
|
|
'help-echo "mouse-1: next server, mouse-3: command menu"
|
|
'keymap sclang-server-mouse-map))
|
|
;; (make-mode-line-mouse-map 'mouse-1 'sclang-mouse-next-server)))
|
|
(address (if (and server (not (eq (plist-get server 'type) 'internal)))
|
|
(format " (%s)" (plist-get server 'address))
|
|
""))
|
|
(info (if running-p
|
|
(mapcar 'number-to-string
|
|
(plist-get (sclang-get-server) 'info))
|
|
'("---" "---" "----" "----" "----" "----"))))
|
|
(apply 'format "%s%s %3s|%3s %% u: %4s s: %4s g: %4s d: %4s" string address info)))
|
|
|
|
(defvar sclang-server-info-string (sclang-get-server-info-string)
|
|
"Info string used in the post buffer mode line.")
|
|
|
|
(defun sclang-update-server-info ()
|
|
"Update server info in the modeline."
|
|
(interactive)
|
|
(sclang-set-server)
|
|
(setq sclang-server-info-string (sclang-get-server-info-string))
|
|
(force-mode-line-update t))
|
|
|
|
;; =====================================================================
|
|
;; language control
|
|
;; =====================================================================
|
|
|
|
(defun sclang-perform-server-command (command &rest args)
|
|
"Perform server COMMAND with ARGS."
|
|
(sclang-eval-string
|
|
(sclang-format
|
|
"Server.named.at(%o.asSymbol).performList(\\tryPerform, %o.asSymbol.asArray ++ %o)"
|
|
sclang-current-server command args)
|
|
nil))
|
|
|
|
(defun sclang-server-boot ()
|
|
"Boot the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "boot"))
|
|
|
|
(defun sclang-server-reboot ()
|
|
"Reboot the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "reboot"))
|
|
|
|
(defun sclang-server-quit ()
|
|
"Quit the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "quit"))
|
|
|
|
(defun sclang-server-free-all ()
|
|
"Free all nodes on the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "freeAll"))
|
|
|
|
(defun sclang-server-display-default ()
|
|
"Display default server."
|
|
(interactive)
|
|
(when sclang-default-server
|
|
(sclang-set-server sclang-default-server)
|
|
(sclang-update-server-info)))
|
|
|
|
(defun sclang-server-make-default ()
|
|
"Make current server the default server."
|
|
(interactive)
|
|
(when sclang-current-server
|
|
(sclang-eval-string
|
|
(sclang-format "
|
|
var server;
|
|
server = Server.named.at(%o);
|
|
if (server.notNil) {
|
|
Server.default = server;
|
|
thisProcess.interpreter.s = server;
|
|
\"Default server: %\n\".postf(server.name);
|
|
};
|
|
" sclang-current-server))
|
|
nil))
|
|
|
|
(defun sclang-server-dump-osc (&optional code)
|
|
"Set the current server's dump OSC mode (with optional CODE)."
|
|
(interactive "P")
|
|
(sclang-perform-server-command "dumpOSC"
|
|
(cond ((consp code) 0)
|
|
((null code) 1)
|
|
(t code))))
|
|
|
|
(defun sclang-server-prepare-for-record (&optional path)
|
|
"Prepare current server for recording a sound file (with optional PATH)."
|
|
(interactive
|
|
(list
|
|
(and current-prefix-arg (read-file-name "Record to file: "))))
|
|
(sclang-perform-server-command "prepareForRecord" path))
|
|
|
|
(defun sclang-server-record ()
|
|
"Record a sound file on the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "record"))
|
|
|
|
(defun sclang-server-pause-recording ()
|
|
"Pause recording on the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "pauseRecording"))
|
|
|
|
(defun sclang-server-stop-recording ()
|
|
"Stop recording on the current server."
|
|
(interactive)
|
|
(sclang-perform-server-command "stopRecording"))
|
|
|
|
(defun sclang-set-server-latency (latency)
|
|
"Set the current server's LATENCY instance variable."
|
|
(interactive "nSet latency: ")
|
|
(sclang-perform-server-command "latency_" latency))
|
|
|
|
(defun sclang-show-server-latency ()
|
|
"Show the current server's latency."
|
|
(interactive)
|
|
(let ((server (sclang-get-server)))
|
|
(message "%s" (and server (plist-get server 'latency)))))
|
|
|
|
(defun sclang-show-server-panel ()
|
|
"Show graphical server panel if available."
|
|
(interactive)
|
|
(sclang-eval-string sclang-server-panel))
|
|
|
|
;; =====================================================================
|
|
;; module setup
|
|
;; =====================================================================
|
|
|
|
(add-hook 'sclang-mode-hook
|
|
(lambda ()
|
|
;; install server mode line in post buffer
|
|
(when (string= (buffer-name) sclang-post-buffer)
|
|
(setq mode-line-format '("-" sclang-server-info-string)))
|
|
;; install server prefix keymap
|
|
(define-key sclang-mode-map "\C-c\C-p" sclang-server-key-map)))
|
|
|
|
(add-hook 'sclang-library-shutdown-hook
|
|
(lambda ()
|
|
(setq sclang-current-server-initialized nil)))
|
|
|
|
|
|
(provide 'sclang-server)
|
|
|
|
;;; sclang-server.el ends here
|