From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: David Kastrup Newsgroups: gmane.emacs.devel Subject: Re: Integrating Midi into Emacs Date: Fri, 09 Jan 2015 22:59:58 +0100 Message-ID: <87lhlbmx7l.fsf@fencepost.gnu.org> References: <87fvbttoa9.fsf@fencepost.gnu.org> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1420878222 27301 80.91.229.3 (10 Jan 2015 08:23:42 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 10 Jan 2015 08:23:42 +0000 (UTC) Cc: emacs-devel@gnu.org To: joakim@verona.se Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Jan 10 09:23:37 2015 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Y9rKa-0006Om-DU for ged-emacs-devel@m.gmane.org; Sat, 10 Jan 2015 09:23:36 +0100 Original-Received: from localhost ([::1]:54507 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9rKZ-0003Tz-I9 for ged-emacs-devel@m.gmane.org; Sat, 10 Jan 2015 03:23:35 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:54359) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9rKA-0002xa-RC for emacs-devel@gnu.org; Sat, 10 Jan 2015 03:23:12 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Y9rK5-0003E2-OE for emacs-devel@gnu.org; Sat, 10 Jan 2015 03:23:10 -0500 Original-Received: from fencepost.gnu.org ([2001:4830:134:3::e]:47419) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9rK5-0003Dq-Jk for emacs-devel@gnu.org; Sat, 10 Jan 2015 03:23:05 -0500 Original-Received: from localhost ([127.0.0.1]:54593 helo=lola) by fencepost.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y9rK4-0003VR-RI; Sat, 10 Jan 2015 03:23:05 -0500 Original-Received: by lola (Postfix, from userid 1000) id DE5D4E0BE1; Fri, 9 Jan 2015 22:59:58 +0100 (CET) In-Reply-To: (joakim@verona.se's message of "Fri, 09 Jan 2015 22:21:18 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:4830:134:3::e X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:181124 Archived-At: --=-=-= Content-Type: text/plain joakim@verona.se writes: > David Kastrup writes: > >> I've been meddling with CCL programs and stuff for integrating Midi >> input received via make-serial-process into Emacs. I've encountered >> several puzzling design decisions and drawbacks. >> >> There are several crucial ones, however. At its core, pressing keys >> on a musical keyboard will result in the insertion of note names into >> the current buffer. This basically is similar to an input method. >> c) the inserted text actually depends on buffer-local variables, for >> example the current notename language (English writes cs for c-sharp, >> Dutch writes cis, Italian writes dod), and the current key (the Midi >> event for c-sharp is indistinguishable from d flat, and the decision is >> made based on the current key in the current piece). Switching CCL >> programs in the decoder is tricky as they do not lend themselves to >> closures with internal states. Also, one would need one closure per >> language/key pairing currently active. >> >> This kind of flexible back-and-forth mapping is actually better >> accomplished by swapping around keymaps rather than encodings. >> >> What this leads up to is that a better approach would be to have Midi >> events in the Emacs event queue. >> >> Thoughts? > > Since you said "Thoughts", I have some. > > - I'm building a combined computer/midi keyboard, and it would > be really nice to use it with emacs with your idea. (If I ever manage > to finish the project) > > - I'm sure you considered OSC, but heres a link anyway: > http://delysid.org/emacs/osc.el Never heard of it. I'll take a look eventually. > My idea with OSC was to embedd gtk sliders in a buffer, and drive a > softsynth made with Overtone with these sliders using OSC. > > Anyway, good luck with your project! Here is the current pitch I am working with without recompiling the binary, so obviously not taking modifier keys or timings at the moment. Also, no strategy yet for encoding key-release events. You just call M-x midikbd-open RET, specify a raw midi device (if necessary, provided by the snd-virmidi module), and then you can choose yourself how you are going to bind the resulting key events. --=-=-= Content-Type: application/emacs-lisp Content-Disposition: inline; filename=midi-kbd.el Content-Transfer-Encoding: quoted-printable ;;; midi-kbd.el --- Create keyboard events from Midi input -*- lexical-bin= ding: t; -*- ;; Copyright (C) 2015 David Kastrup ;; Author: David Kastrup ;; Keywords: convenience, hardware, multimedia ;; 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 3 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, see . ;;; Commentary: ;; This generates events from an ALSA Midi device. The names of the ;; events are modeled after the nomenclature of Emacs Calc's notenames. ;; Channel switching events are ... ;; Note Events are ... ;; Since Midi does not encode enharmonics, there are no *flat_* key ;; names: it is the job of the key bindings to establish tonality ;; beyond the chromatic pitch. ;; ;; It would make sense to provide this kind of functionality directly ;; from within Emacs, making use of libportmidi. That way, it could ;; get supported by operating systems not providing a raw Midi port ;; accessible as a character device. This would also improve the ;; possibilities to integrate timing and modifiers into events like it ;; is done with mouse events. ;;; Code: ;; Should this be a char-table? (defvar midikbd-keys [C_-1 Csharp_-1 D_-1 Dsharp_-1 E_-1 F_-1 Fsharp_-1 G_-1 Gsharp_-1 A_-1 Asharp_-1 B_-1 C_0 Csharp_0 D_0 Dsharp_0 E_0 F_0 Fsharp_0 G_0 Gsharp_0 A_0 Asharp_0 B_0 C_1 Csharp_1 D_1 Dsharp_1 E_1 F_1 Fsharp_1 G_1 Gsharp_1 A_1 Asharp_1 B_1 C_2 Csharp_2 D_2 Dsharp_2 E_2 F_2 Fsharp_2 G_2 Gsharp_2 A_2 Asharp_2 B_2 C_3 Csharp_3 D_3 Dsharp_3 E_3 F_3 Fsharp_3 G_3 Gsharp_3 A_3 Asharp_3 B_3 C_4 Csharp_4 D_4 Dsharp_4 E_4 F_4 Fsharp_4 G_4 Gsharp_4 A_4 Asharp_4 B_4 C_5 Csharp_5 D_5 Dsharp_5 E_5 F_5 Fsharp_5 G_5 Gsharp_5 A_5 Asharp_5 B_5 C_6 Csharp_6 D_6 Dsharp_6 E_6 F_6 Fsharp_6 G_6 Gsharp_6 A_6 Asharp_6 B_6 C_7 Csharp_7 D_7 Dsharp_7 E_7 F_7 Fsharp_7 G_7 Gsharp_7 A_7 Asharp_7 B_7 C_8 Csharp_8 D_8 Dsharp_8 E_8 F_8 Fsharp_8 G_8 Gsharp_8 A_8 Asharp_8 B_8 C_9 Csharp_9 D_9 Dsharp_9 E_9 F_9 Fsharp_9 G_9 Channel1 Channel2 Channel3 Channel4 Channel5 Channel6 Channel7 Channel8 Channel9 Channel10 Channel11 Channel12 Channel13 Channel14 Channel15 Cha= nnel16] "Map CCL program codes to symbols used as keycodes. CCL program `midikbd-decoder' produces 0..127 for the pitches and 128..143 for the channel switches. `midikbd-keys' maps this into symbols used as keycodes.") ;; CCL programs used in coding systems apparently don't save registers ;; across suspension so we don't use a coding system. Instead our CCL ;; program is run using ccl-execute-on-string in the filter routine. ;; That allows us to interpret all _completed_ Midi commands without ;; getting confused, and it also gives us a well-defined internal ;; state (namely one for every call of midikbd-filter-create). (define-ccl-program midikbd-decoder '(1 ((r1 =3D 16) (loop (read r0) (if ((r0 & 240) =3D=3D 144) (read-if (r2 < 128) ; pitch (read-if (r3 > 0) ; velocity ; Some Midi devices use velocity 0 ; for switching notes off, so skip ; velocity 0 notes ((r0 &=3D 15) (if (r0 !=3D r1) ((r1 =3D r0) (write (r0 + 128)))) (write-repeat r2))))) (repeat))))) (defun midikbd-filter-create () "Create one Midi process filter keeping state across calls." (let ((state (make-vector 9 nil))) (lambda (_process string) (setq unread-command-events (nconc unread-command-events (mapcar (lambda (x) (aref midikbd-keys x)) (ccl-execute-on-string 'midikbd-decoder state string t t))))))) ;;;###autoload (defun midikbd-open (file) "Open the raw Midi device FILE as a source for Midi input. This should be an ALSA device like \"/dev/snd/midiC1D0\". If your Midi producing device is a software Midi device, you might need to call sudo modprobe snd-virmidi in order to have some virtual ALSA ports available as such raw Midi devices." (interactive (list (read-file-name "Midi device: " "/dev/snd/" "midiC1D0" t nil #'file-readable-p))) (let* ((file (expand-file-name file "/dev/snd/")) (buffer (get-buffer-create (concat " *Midi process " file " *"))) (oldproc (get-buffer-process buffer))) (if (processp oldproc) (delete-process oldproc)) (make-serial-process :port file :speed nil :buffer buffer :coding 'raw-text :filter (midikbd-filter-create) :sentinel #'ignore :noquery t))) (provide 'midi-kbd) ;;; midi-kbd.el ends here --=-=-= Content-Type: text/plain Of course this is ongoing work, but what I got here is a nice self-contained module doing exactly one job, that of delivering events. And obviously, if one were to write native Midi support, that's exactly the scope of what this native Midi support would be supposed to do. -- David Kastrup --=-=-=--