- [Function]
(
set-receiver!
hook stream)
Installs hook to receive stream data as soon as
it arrives from an external application. No values are returned
by set-receiver!
or
by hook. Receiving remains in effect until canceled by
remove-receiver!.
The calling syntax of hook depends on stream:
- If stream is a portmidi-stream then hook is passed two arguments, the values of which depend on the receive mode of stream.
- If stream is a midishare-stream then hook is passed one argument, a MidiEv foreign object.
- If stream is an sc-stream then blah blah blah.
- If stream is boolean true then hook is a thunk (a function of no arguments) that will be called every millisecond. The hook is responsible for reading whatever ports are necessary. See receive for information about explicitly reading input from streams.
Implementation and Limitations:
Receiving is implemented in the following Lisp/OS combinations:
- OpenMCL on OS X
- SBCL (0.9.0 or higher) on Linux
- CMUCL (19b or higher) on Linux
- Gauche Scheme (planned)
From the caller's perspective hook appears to receive data asynchronously but actually receiving is always polling in some manner; how this polling is implemented depends on what facilities the host Lisp provides. CM utilizes two different strategies for implementing non-blocking receiving:
- Periodic polling [OpenMCL, CMUCL, SBCL]: the host Lisp provides the ability to periodically call a function in the main Lisp process without blocking the REPL.
- Threaded polling [OpenMCL, Gauche]: each receiver runs in its own native thread.
Examples:
Example 1. Receiving input from Portmidi.
;;; open with no latency for interactive work. the input and ;;; output device ids to open will depend on your MIDI setup. (define *pm* (portmidi-open :input 1 :output 3 :latency 0)) ;;; a midi through (set-receiver! (lambda (mm ms) ms (output mm :to *pm*)) *pm*) ;;; play your keyboard...then (remove-receiver! *pm*) ;;; make a harmonizer (set-receiver! (lambda (mm ms) ms (if (or (note-on-p mm) (note-off-p mm)) (let ((k (note-on-key mm))) (output mm :to *pm*) (output (midi-copy-message mm :data1 (+ k 3)) :to *pm*) (output (midi-copy-message mm :data1 (+ k 7)) :to *pm*)))) *pm*) ;;; play your keyboard...then (remove-receiver! *pm*) (portmidi-close)
Example 2. Using a receiver to trigger processes in rts
.
(define (tonto len knum wai amp) (process repeat len output (new midi :time (now) :duration .1 :amplitude amp :keynum (between knum (+ knum 12))) wait wai)) (define (trigger mm ms) ms (if (note-on-p mm) (sprout (tonto 10 (note-on-key mm) .1 (/ (note-on-velocity mm) 127.0))))) (define *pm* (portmidi-open :input 1 :output 3 :latency 0)) (rts #f *pm*) (set-receiver! #'trigger *pm*) ;;; play your keyboard...then (remove-receiver! *pm*) (rts-stop) (portmidi-close)