gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

musical-letters.el


From: Joe Corneli
Subject: musical-letters.el
Date: Mon, 24 May 2004 20:05:00 -0500

This minor mode provides support for playing the free software
synthesizer fluidsynth while you type in emacs.  The mode should be
considered to be quite preliminary, as it has known bugs and does
not give access to the full power of fluidsynth.  However, because
the mode is such fun to use and I have some questions about it, I
figured I would post it for others to examine or try out.

My questions: (1) I am having trouble binding note events to
non-ascii characters, why?  (2) I see a bug when I start up the
inferior shell, why?  (3) Running fluidsynth as a comint process
seems to result in a "live" fluidsynth that nevertheless produces no
noise, why?

But anyway, as long as you check the value of musical-letters-font
to make sure it works with your setup, musical-letters-mode should
work.

The development copy will reside at the following URL:

http://www.ma.utexas.edu/~jcorneli/a/elisp/musical-letters.el

Feedback is welcome.  I'll notify you of any major updates.

;;; musical-letters.el -- play the fluidsynth software synthesizer

;; Copyright (C) 2004 Joe Corneli <address@hidden>

;; Time-stamp: <jac -- Mon May 24 19:45:17 CDT 2004>

;; This file is not part of GNU Emacs, but it is distributed under
;; the same terms as GNU Emacs.

;; GNU Emacs 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, or (at your
;; option) any later version.

;; GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; The flow in `musical-letters-mode' is from the keyboard to Emacs,
;; and from Emacs to Fluidsynth.  At the Emacs stage, two things
;; happen: When a printing character (or, more accurately one of the
;; printing characters that is on our list; hereafter, a "letter") is
;; pressed, it is inserted into the buffer; then a code associated
;; with this letter is sent to fluidsynth, which plays a note.

;; The user can change the code values that are sent to fluidsynth by
;; setting the variable `musical-letters-tuning'.  Currently only one
;; sound font file at a time is supported; the user can change this
;; font by setting the variable `musical-letters-font'.

;;; History:

;; The author began experimenting with the idea of musical letters in
;; the summer of 2002.  We now have a demo system that combines music
;; with typing a very _fluid_ and, I think, elegant way.  Its even
;; fairly platform-independent, thanks to the efforts of the
;; fluidsynth and emacs developers -- wow!  Future plans include
;; extending this mode to record typed music using proper musical
;; notation.

;;; Code:

(defvar musical-letters-tuning "default"
  "Controls which keys produce which notes.
Set with the command `musical-letters-set-tuning'.")

(defvar musical-letters-font "~/sf2/VintageDreamsWaves-v2.sf2"
  "Sound font used in `musical-letters-mode'.")

;; additional fonts should be a customizable list.  Should figure out
;; how to make fluidsynth load them and how to make it switch between
;; them.

;; would be potentially a good idea to just have a command for sending
;; an arbitrary string to the inferior fluidsynth process.

;; probably the list of layouts should be customizable, and this
;; should complete over that list.
(defun musical-letters-set-tuning (tuning)
  "Chose TUNING by which notes correspond to keys.
The standard choices are \"default\", which is tuned
to the ASCII system, \"basic dvorak\", and  \"basic qwerty\".
The \"full dvorak\" tuning is present, but not fully 
supported."
  (interactive (list (completing-read "Tuning: "
                                      '("default"
                                       "basic dvorak"
                                       "basic qwerty"
                                       "full dvorak"))))
  (setq musical-letters-tuning tuning))

(define-minor-mode musical-letters-mode
  "Toggle musical letters mode.
With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.

When musical letters mode is enabled, keypresses
insert letters and play notes through the fluidsynth
software synthesizer."
  :init-value nil
  :lighter " Musical"
  :keymap '(("a" . (lambda () (interactive) (fs-c "a")))
            ("b" . (lambda () (interactive) (fs-c "b")))
            ("c" . (lambda () (interactive) (fs-c "c")))
            ("d" . (lambda () (interactive) (fs-c "d")))
            ("e" . (lambda () (interactive) (fs-c "e")))
            ("f" . (lambda () (interactive) (fs-c "f")))
            ("g" . (lambda () (interactive) (fs-c "g")))
            ("h" . (lambda () (interactive) (fs-c "h")))
            ("i" . (lambda () (interactive) (fs-c "i")))
            ("j" . (lambda () (interactive) (fs-c "j")))
            ("k" . (lambda () (interactive) (fs-c "k")))
            ("l" . (lambda () (interactive) (fs-c "l")))
            ("m" . (lambda () (interactive) (fs-c "m")))
            ("n" . (lambda () (interactive) (fs-c "n")))
            ("o" . (lambda () (interactive) (fs-c "o")))
            ("p" . (lambda () (interactive) (fs-c "p")))
            ("q" . (lambda () (interactive) (fs-c "q")))
            ("r" . (lambda () (interactive) (fs-c "r")))
            ("s" . (lambda () (interactive) (fs-c "s")))
            ("t" . (lambda () (interactive) (fs-c "t")))
            ("u" . (lambda () (interactive) (fs-c "u")))
            ("v" . (lambda () (interactive) (fs-c "v")))
            ("w" . (lambda () (interactive) (fs-c "w")))
            ("x" . (lambda () (interactive) (fs-c "x")))
            ("y" . (lambda () (interactive) (fs-c "y")))
            ("z" . (lambda () (interactive) (fs-c "z")))
            ("A" . (lambda () (interactive) (fs-c "A")))
            ("B" . (lambda () (interactive) (fs-c "B")))
            ("C" . (lambda () (interactive) (fs-c "C")))
            ("D" . (lambda () (interactive) (fs-c "D")))
            ("E" . (lambda () (interactive) (fs-c "E")))
            ("F" . (lambda () (interactive) (fs-c "F")))
            ("G" . (lambda () (interactive) (fs-c "G")))
            ("H" . (lambda () (interactive) (fs-c "H")))
            ("I" . (lambda () (interactive) (fs-c "I")))
            ("J" . (lambda () (interactive) (fs-c "J")))
            ("K" . (lambda () (interactive) (fs-c "K")))
            ("L" . (lambda () (interactive) (fs-c "L")))
            ("M" . (lambda () (interactive) (fs-c "M")))
            ("N" . (lambda () (interactive) (fs-c "N")))
            ("O" . (lambda () (interactive) (fs-c "O")))
            ("P" . (lambda () (interactive) (fs-c "P")))
            ("Q" . (lambda () (interactive) (fs-c "Q")))
            ("R" . (lambda () (interactive) (fs-c "R")))
            ("S" . (lambda () (interactive) (fs-c "S")))
            ("T" . (lambda () (interactive) (fs-c "T")))
            ("U" . (lambda () (interactive) (fs-c "U")))
            ("V" . (lambda () (interactive) (fs-c "V")))
            ("W" . (lambda () (interactive) (fs-c "W")))
            ("X" . (lambda () (interactive) (fs-c "X")))
            ("Y" . (lambda () (interactive) (fs-c "Y")))
            ("Z" . (lambda () (interactive) (fs-c "Z")))
            ("'" . (lambda () (interactive) (fs-c "'")))
            ("," . (lambda () (interactive) (fs-c ",")))
            ("." . (lambda () (interactive) (fs-c ".")))
            (";" . (lambda () (interactive) (fs-c ";")))
            ("1" . (lambda () (interactive) (fs-c "1")))
            ("2" . (lambda () (interactive) (fs-c "2")))
            ("3" . (lambda () (interactive) (fs-c "3")))
            ("4" . (lambda () (interactive) (fs-c "4")))
            ("5" . (lambda () (interactive) (fs-c "5")))
            ("6" . (lambda () (interactive) (fs-c "6")))
            ("7" . (lambda () (interactive) (fs-c "7")))
            ("8" . (lambda () (interactive) (fs-c "8")))
            ("9" . (lambda () (interactive) (fs-c "9")))
            ("0" . (lambda () (interactive) (fs-c "0")))
            ("!" . (lambda () (interactive) (fs-c "!")))
            ("@" . (lambda () (interactive) (fs-c "@")))
            ("#" . (lambda () (interactive) (fs-c "#")))
            ("$" . (lambda () (interactive) (fs-c "$")))
            ("%" . (lambda () (interactive) (fs-c "%")))
            ("^" . (lambda () (interactive) (fs-c "^")))
            ("&" . (lambda () (interactive) (fs-c "&")))
            ("*" . (lambda () (interactive) (fs-c "*")))
            ("(" . (lambda () (interactive) (fs-c "(")))
            (")" . (lambda () (interactive) (fs-c ")")))
            ("?" . (lambda () (interactive) (fs-c "?")))
            ("/" . (lambda () (interactive) (fs-c "/")))
            ("_" . (lambda () (interactive) (fs-c "_")))
            ("-" . (lambda () (interactive) (fs-c "-")))
            ("<" . (lambda () (interactive) (fs-c "<")))
            (">" . (lambda () (interactive) (fs-c ">")))
            (":" . (lambda () (interactive) (fs-c ":")))
            ("[" . (lambda () (interactive) (fs-c "[")))
            ("]" . (lambda () (interactive) (fs-c "]")))
            ("{" . (lambda () (interactive) (fs-c "{")))
            ("}" . (lambda () (interactive) (fs-c "}")))
            ("\"" . (lambda () (interactive) (fs-c "\"")))
            ("\\" . (lambda () (interactive) (fs-c "\\")))
            ;; These keys are for my full dvorak layout.
            ;; They don't seem to actually work however.
            ;; this is the case even though running  
            ;; `(fs-c "<key>")' seems to work out fine.
            ;; so for some reason they don't seem to be
            ;; bound properly.
            ("í" . (lambda () (interactive) (fs-c "í")))
            ("ì" . (lambda () (interactive) (fs-c "ì")))
            ("è" . (lambda () (interactive) (fs-c "è")))
            ("é" . (lambda () (interactive) (fs-c "é")))
            ("ù" . (lambda () (interactive) (fs-c "ù")))
            ("Í" . (lambda () (interactive) (fs-c "Í")))
            ("Ì" . (lambda () (interactive) (fs-c "Ì")))
            ("È" . (lambda () (interactive) (fs-c "È")))
            ("É" . (lambda () (interactive) (fs-c "É")))
            ("Ù" . (lambda () (interactive) (fs-c "Ù")))
            ("£" . (lambda () (interactive) (fs-c "£")))
            ("¥" . (lambda () (interactive) (fs-c "¥"))))
  ;; body

  ;; A bit more commentary on the mode:

  ;; We may want to load more than just one font in a more advanced
  ;; version of this mode.

  ;; Also, if for some reason we wanted to have different buffers to
  ;; have different fluidsynths associated with them, we'd have to
  ;; change the code around to support that.

  (if musical-letters-mode
      ;; (i.e. we just turned it on)
; This is what we _should_ probably run, but for some reason the
; fluidsynth that is instantiated by this code is totally silent.
; Weird.
;;;      (if (not (comint-check-proc "*fluid*"))
;;;          (make-comint "fluid" "fluidsynth" nil musical-letters-font))
      (save-window-excursion (shell "*fluid*")
                             (insert (concat "fluidsynth "
                                             musical-letters-font))
                             (comint-send-input))
    ;; there is perhaps no particular reason to kill the *fluid* buffer
    ))

;; note: I use my own slightly modified version of dvorak; there are a
;; few slight discrepancies with the usual one (though they aren't in
;; the core layout, but rather in the periphery).  The basic layout
;; (common to all dvoraks) is given here.

(defvar basic-dvorak-list
  '(("1" . "90")("2" . "91")("3" . "92")("4" . "93")("5" . "94")("6" . 
"95")("7" . "96")("8" . "97")("9" . "98")("0" . "99")
    ("'" . "80")("," . "81")("." . "82")("p" . "83")("y" . "84")("f" . 
"85")("g" . "86")("c" . "87")("r" . "88")("l" . "89")
    ("a" . "70")("o" . "71")("e" . "72")("u" . "73")("i" . "74")("d" . 
"75")("h" . "76")("t" . "77")("n" . "78")("s" . "79")
    (";" . "60")("q" . "61")("j" . "62")("k" . "63")("x" . "64")("b" . 
"65")("m" . "66")("w" . "67")("v" . "68")("z" . "69")
    ;; shifted
    ("!" . "50")("@" . "51")("#" . "52")("$" . "53")("%" . "54")("^" . 
"55")("&" . "56")("*" . "57")("(" . "58")(")" . "59")
   ("\"" . "40")("," . "41")("." . "42")("P" . "43")("Y" . "44")("F" . 
"45")("G" . "46")("C" . "47")("R" . "48")("L" . "49")
    ("A" . "30")("O" . "31")("E" . "32")("U" . "33")("I" . "34")("D" . 
"35")("H" . "36")("T" . "37")("N" . "38")("S" . "39")
    (":" . "20")("Q" . "21")("J" . "22")("K" . "23")("X" . "24")("B" . 
"25")("M" . "26")("W" . "27")("V" . "28")("Z" . "29"))
  "The common Dvorak keyboard layout, set to music.")

;; Similarly, here is the common QWERTY layout.

(defvar basic-qwerty-list
  '(("1" . "90")("2" . "91")("3" . "92")("4" . "93")("5" . "94")("6" . 
"95")("7" . "96")("8" . "97")("9" . "98")("0" . "99")
    ("q" . "80")("w" . "81")("e" . "82")("r" . "83")("t" . "84")("y" . 
"85")("u" . "86")("i" . "87")("o" . "88")("p" . "89")
    ("a" . "70")("s" . "71")("d" . "72")("f" . "73")("g" . "74")("h" . 
"75")("j" . "76")("k" . "77")("l" . "78")(";" . "79")
    ("z" . "60")("x" . "61")("c" . "62")("v" . "63")("b" . "64")("n" . 
"65")("m" . "66")("," . "67")("." . "68")("/" . "69")
    ;; shifted
    ("!" . "50")("@" . "51")("#" . "52")("$" . "53")("%" . "54")("^" . 
"55")("&" . "56")("*" . "57")("(" . "58")(")" . "59")
    ("Q" . "40")("W" . "41")("E" . "42")("R" . "43")("T" . "44")("Y" . 
"45")("U" . "46")("I" . "47")("O" . "48")("P" . "49")
    ("A" . "30")("S" . "31")("D" . "32")("F" . "33")("G" . "34")("H" . 
"35")("J" . "36")("K" . "37")("L" . "38")(";" . "39")
    ("Z" . "20")("X" . "21")("C" . "22")("V" . "23")("B" . "24")("N" . 
"25")("M" . "26")("<" . "27")(">" . "28")("?" . "29"))
  "The common QWERTY keyboard layout, set to music.")

;; there are lots of different layout possibilities available for us
;; to try!

;; this one is not considered to be "supported", though its cool.  I
;; am having trouble binding the latin-non-ascii keys.
(defvar full-dvorak-list
  '(("£" . "93")  ("è" . "81")  ("ù" . "70")  ("ì" . "58")
    ("1" . "94")  ("'" . "82")  ("a" . "70")  (";" . "59")
    ("2" . "95")  ("," . "83")  ("o" . "71")  ("q" . "60")
    ("3" . "96")  ("." . "84")  ("e" . "72")  ("j" . "61")
    ("4" . "97")  ("p" . "85")  ("u" . "73")  ("k" . "62")
    ("5" . "98")  ("y" . "86")  ("i" . "74")  ("x" . "63")
    ("6" . "99")  ("f" . "87")  ("d" . "75")  ("b" . "64")
    ("7" . "100") ("g" . "88")  ("h" . "76")  ("m" . "65")
    ("8" . "101") ("c" . "89")  ("t" . "77")  ("w" . "66")
    ("9" . "102") ("r" . "90")  ("n" . "78")  ("v" . "67")
    ("0" . "103") ("l" . "91")  ("s" . "79")  ("z" . "68")
    ("/" . "104") ("é" . "92")  ("\\" . "80") ("í" . "69")
    ;; shifted
    ("¥" . "46")  ("È" . "34")  ("Ù" . "22")  ("Ì" . "10")
    ("!" . "47")  ("\"" . "35") ("A" . "23")  (":" . "11")
    ("@" . "48")  ("," . "36")  ("O" . "24")  ("Q" . "12")
    ("#" . "49")  ("." . "37")  ("E" . "25")  ("J" . "13")
    ("$" . "50")  ("P" . "38")  ("U" . "26")  ("K" . "14")
    ("%" . "51")  ("Y" . "39")  ("I" . "27")  ("X" . "15")
    ("^" . "52")  ("F" . "40")  ("D" . "28")  ("B" . "16")
    ("&" . "53")  ("G" . "41")  ("H" . "29")  ("M" . "17")
    ("*" . "54")  ("C" . "42")  ("T" . "30")  ("W" . "18")
    ("(" . "55")  ("R" . "43")  ("N" . "31")  ("V" . "19")
    (")" . "56")  ("L" . "44")  ("S" . "32")  ("Z" . "20")
    ("?" . "57")  ("É" . "45")  ("|" . "33")  ("Í" . "21")
    )
  "My full (modded) Dvorak-based keyboard layout, set to music.")

;; This is the main sound generator!  Check it out.
(defun fs-c (input)
  "Fluidsynth command engine.
For given INPUT, create a fluidsynth command
according to the current tuning, and send the command
to fluidsynth."
(insert input)
  (save-excursion
    (set-buffer (get-buffer "*fluid*"))
    (cond ((equal musical-letters-tuning "default")
           (insert "noteon 0 "
                   (int-to-string
                    (- (string-to-char input) 33)) " 95"))
          ((equal musical-letters-tuning "basic dvorak")
           (insert "noteon 0 "
                   (let ((key (cdr (assoc input basic-dvorak-list))))
                     (if key
                         key
                       "1")) " 95"))
          ((equal musical-letters-tuning "basic qwerty")
           (insert "noteon 0 "
                   (let ((key (cdr (assoc input basic-qwerty-list))))
                     (if key
                         key
                       "1")) " 95"))
          ((equal musical-letters-tuning "full dvorak")
           (insert "noteon 0 "
                   (let ((key (cdr (assoc input full-dvorak-list))))
                     (if key
                         key
                       "1")) " 95")))
    (comint-send-input)))

(provide 'musical-letters)

;;; musical-letters.el ends here




reply via email to

[Prev in Thread] Current Thread [Next in Thread]