[plt-scheme] OS X Core MIDI and DrScheme
First some background:
I teach a high school CS course using HtDP. I also teach a computer music
course which has a component on algorithmic composition. Recently I
stumble upon a Scheme based tool for OS X called impromptu which provides
direct access to the Core MIDI drivers (specifically one has access to the
audio units). It is a nifty little tool but the Scheme environment is far
inferior to what is available in DrScheme and I would like to be able to
cross-fertilize between the CS course and the music course.
So here are my questions:
* Is anyone familiar with impromptu?
*How hard would it be to incorporate such capabilities into DrScheme? (or
are such things already available and I haven't looked in the correct
places?)
*Is this the correct list for asking such a question? (the HtDP list
didn't seem like the correct place)
*Are there any audio and/or music capabilities/libraries for DrScheme,
specifically something which can interface with MIDI and/or Core Audio,
beyond the Teachpacks which are already bundled?
To give a sense of how impromptu works here is a snippet of code. I would
like to be able to bring this into the realm of the design recipe approach
of HtDP and I would like to be able to bring the full power of MrEd to
this tool.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; PIANO PHASE EXAMPLE
;;
;; Define and play Steve Reich Piano Phase
;;
;; Create a play-sequence function that
;; loops using a quasi-recursive timed
;; callback.
;;
;; Try changing some of the values in the
;; pitch list while play-sequence is looping.
;; You should hear your changes take effect
;; on the next callback loop.
;;
;; While piano phase is playing try adding
;; the line (play-note time inst 95 80 1.0)
;; to the start of the play-sequence
;; function and re-evaluate.
;;
;; (define (play-sequence time inst inc)
;; (play-note time inst 95 80 1.0)
;; (map (lambda (p d r)
;; ...
;; ...
;; )))
;;
;; The newly evaluated function will be
;; automatically called by callback on the next
;; cycle. The ability to re-define functions in
;; callback loops at runtime is a handy
;; live programming technique.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; make sure that nothing is already connected
(au-clear-graph)
; setup simple au graph
; piano -> output
(define piano (au-create-node "aumu" "dls " "appl"))
(au-connect-node piano 0 *au-output-node* 0)
(au-update-graph)
(program-change (now) piano 0)
; define a Cmajor scale
(define *pitches* '(64 66 71 73 74 66 64 73 71 64 74 73))
(define *pitches2* '(73 66 71 64 74 66 69 73 71 64 74 73))
(define *pitches3* '(64 66 69 73 74 66 ))
(define *pitches4* '(64 73 71 64 74 73))
; choose random dynamics
(define *dynamics* (make-list (length *pitches*)
(lambda (i) (random 50 110))))
(define *rhythms* (make-list (length *pitches*) 0.18))
(define *rhythms2* (make-list (length *pitches2*) 0.18))
(define *rhythms3* (make-list (length *pitches3*) 0.18))
(define *go* #t)
; loop a note sequence incrementing 'time'
; by the previous rhythm value. Allow
; for an increment value that will slighly
; delay playback.
;
; Rhythm values (in beats) need to be multipled by
; *second* to provide a number in samples.
(define (play-sequence time inst inc)
(map (lambda (p d r)
(play-note time inst p d r)
(set! time (+ time (* r *second*))))
*pitches*
*dynamics*
*rhythms*)
(if *go*
(callback time 'play-sequence (+ time inc) inst inc)))
; loop a note sequence incrementing 'time'
; by the previous rhythm value. Allow
; for an increment value that will slighly
; delay playback.
;
; Rhythm values (in beats) need to be multipled by
; *second* to provide a number in samples.
(define (play-sequence2 time inst inc)
(map (lambda (p d r)
(play-note time inst p d r)
(set! time (+ time (* r *second*))))
*pitches2*
*dynamics*
*rhythms2*)
(if *go*
(callback time 'play-sequence2 (+ time inc) inst inc)))
; loop a note sequence incrementing 'time'
; by the previous rhythm value. Allow
; for an increment value that will slighly
; delay playback.
;
; Rhythm values (in beats) need to be multipled by
; *second* to provide a number in samples.
(define (play-sequence3 time inst inc)
(map (lambda (p d r)
(play-note time inst p d r)
(set! time (+ time (* r *second*))))
*pitches3*
*dynamics*
*rhythms3*)
(if *go*
(callback time 'play-sequence3 (+ time inc) inst inc)))
(define (play-sequence4 time inst inc)
(map (lambda (p d r)
(play-note time inst p d r)
(set! time (+ time (* r *second*))))
*pitches4*
*dynamics*
*rhythms3*)
(if *go*
(callback time 'play-sequence4 (+ time inc) inst inc)))
; start two sequence with a phase of 500 samples
(define (start time)
(set! *go* #t)
(play-sequence time piano 0)
(play-sequence2 time piano 23)
(play-sequence3 time piano 109)
(play-sequence time piano 220)
(play-sequence4 time piano 30)
(play-sequence time piano 500))
(define (stop)
(set! *go* #f))
; STOP
(stop)
; START
(start (now))
Paul C. Fisher
Science Department / Director of Technology
Morristown-Beard School
http://www.mobeard.org/