Skip to content

A Common Lisp library for MIDI in Linux via ALSA.

Notifications You must be signed in to change notification settings

defaultxr/cl-alsa-midi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cl-alsa-midi

This is cl-alsa-midi, a Common Lisp library for MIDI in Linux via ALSA. With it, you can send and receive MIDI messages to and from any program or device that is supported by ALSA.

Currently, this library is in the process of being refactored:

  • Remove extraneous/unneeded features.
  • Reduce dependencies - in particular optima and optima.extra.
  • Improve/clean up the code style (remove unnecessary macros, fix indentation, etc).
  • Add more docstrings/documentation.
  • Simplify and stabilize the API - integrate cl-alsa-midi/quick and midihelper into the main cl-alsa-midi package.
  • Add more tests.
  • Submit to Quicklisp (after most of the above is complete–in particular, API improvement/stabilization).

This library is based off of cl-alsaseq, originally written by Richard Venn. It cleans up the library, removing the sequencer functionality and other non-essential parts, and simplifying the interface.

Example

Here is a simple example of how to use cl-alsa-midi.

Note that in the future cl-alsa-midi’s API will change and this example will stop working. If you just need a stable API that you can rely on, you should use cl-alsaseq for now instead.

(ql:quickload :cl-alsa-midi) ; Load the system.

;; Define a basic handler function for MIDI input.
(defun midi-map (messages)
  (dolist (message messages)
    (let* ((event-type (getf message :event-type))
           (event-data (getf message :event-data))
           (source (car (getf message :source)))
           (destination (car (getf message :dest))))
      (declare (ignorable source destination))
      (format t "~A: ~S~%"
              (case event-type
                (:snd_seq_event_noteon "Note on")
                (:snd_seq_event_noteoff "Note off")
                (:snd_seq_event_controller "CC")
                (t event-type))
              event-data))))

;; Start the ALSA MIDI client with midi-map function as input handler.
(cl-alsa-midi/midihelper:midihelper-start :master 96 'midi-map)

;; ...Then connect the "CL" ALSA MIDI source to the destination of your choice.
;; I usually use Qjackctl to manage MIDI connections.

(defparameter *midi-channel* 0)

(cl-alsa-midi/midihelper:send-event (cl-alsa-midi/midihelper:ev-noteon *midi-channel* 69 127)) ; Send a MIDI note on event. 69 is the note number, 127 is the velocity

(cl-alsa-midi/midihelper:send-event (cl-alsa-midi/midihelper:ev-noteoff *midi-channel* 69 127)) ; Send a MIDI note off to stop the previous note.

(cl-alsa-midi/midihelper:send-event (cl-alsa-midi/midihelper:ev-pgmchange *midi-channel* 2)) ; Send a program change message to switch to program #2.

To use cl-alsa-midi to trigger synths with cl-collider, you can do something like the following:

(ql:quickload '(:cl-alsa-midi :cl-collider)) ; Load the systems.

(defvar *midi-map-synths-playing* (make-hash-table)
  "Hash table mapping MIDI note numbers to the synth/node that they triggered.")

(defparameter *midi-map-synth* 'default
  "Name of the synth that should be triggered by incoming MIDI notes.")

;; Define a basic handler function for MIDI input.
(defun midi-map (messages)
  (dolist (message messages)
    (let* ((event-type (getf message :event-type))
           (event-data (getf message :event-data))
           (source (car (getf message :source)))
           (destination (car (getf message :dest))))
      (declare (ignorable source destination))
      (case event-type
        (:snd_seq_event_noteon
         (let ((note (getf event-data 'cl-alsa-midi::note)))
           (setf (gethash note *midi-map-synths-playing*) (sc:synth *midi-map-synth* :freq (sc:midicps note)))))
        (:snd_seq_event_noteoff
         (let* ((note (getf event-data 'cl-alsa-midi::note))
                (synth (gethash note *midi-map-synths-playing*)))
           (when synth
             (sc:release synth)
             (setf (gethash note *midi-map-synths-playing*) nil))))
        (:snd_seq_event_controller nil)
        (t event-type)))))

;; Start the ALSA MIDI client with midi-map function as input handler.
(cl-alsa-midi/midihelper:midihelper-start :master 96 'midi-map)

Similar

The original library that cl-alsa-midi is based off of.

Portmidi bindings for Common Lisp.

About

A Common Lisp library for MIDI in Linux via ALSA.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published