Critique a beginner's code!

Larry Troxler lt@westnet.com
Fri, 15 Nov 1996 22:41:26 -0500 (EST)


Thanks Rick,Tobias, and the other list members for helping this beginner so
far. Unfortunately for you,  I am paying you back by offering the following
code for you to critique :-). At this stage, I have a number of questions,
mostly minor details, and I thought it would make the most sense simply to
post some code, with my questions embedded in the comments. So, if anyone
has the time to look through this, I would welcome any suggestions, either
specifically regarding the questions I raise, or more generally, pointing to
ways I should be doing things differently. Thanks in advance, everyone!

Also let me know if the line-formatting gets mangled in transit - if so I
will repost.

Larry Troxler
lt@westnet.com

-----------

;;; A first stab at MIDI creation in CM. Please read through questions in
comments below
;;; and critique! Thanks!

(setf opus-len 60) ; quit after a minute

;;; The following is so we can use names instead of numbers for MIDI program
changes.
(setf patches 
   '((Org400 8)
     (Vulcan-Harp 21)))

;;; This maintains the current MIDI program (patch) for each channel, should
probably 
;;; be local to the "pnote" class below - Suggestions, anyone?
(setf cur-chan-pat (make-array 16 :initial-element nil))    

;;; "pnote" is a MIDI note which includes a patch parameter. If the "patch"
parameter is 
;;;  different from
;;; the patch currently being played on a given channel, then write-event
will send the
;;; new program change before the note. What I don't know how to do is to
schedule the 
;;; the program change a couple ticks in advance of the note, for synths
that require it.

(defobject pnote (midi-note)
  ((patch :initarg :patch :initform nil :accessor pnote-patch)))

;;; modeled after the detuned MIDI note class - the guts haven't been tested
thuroughly but 
;;; hopefully you understand the concept here.
(defmethod write-event ((me pnote ) file)
  (let ((patchnum (second (assoc (pnote-patch me) patches)))) ; symbol -> number
    (unless 
     (eql patchnum (aref cur-chan-pat (slot-value me 'channel))) ; unless
same patch on this channel,
     (setf (aref cur-chan-pat (slot-value me 'channel)) patchnum) ; register
new patch.
     (let ((obj (object midi-message                              ; send the
program change.
                        message (make-program-change 
                                 (slot-value me 'channel)
                                 patchnum))))
       (setf (slot-value obj 'time) (slot-value me 'time))
       (write-event obj file))))
  (call-next-method))  ; Always send the original midi-note (obviously)

;;; Now for the specific task at hand.
;;; Following are the two algorithms that will be run for this experiment.

;;; The "Org400" part
(defun do-Org400 (chan)
 (algorithm
  Org400 pnote ( 
                 patch 'Org400 
                 start 0 
                 channel chan 
                 end (- opus-len 1)
                 amplitude (amplitude 'mf) ; syntax is a bit awkward - why
can't symbolic values
                 duration (rhythm '32))    ; be directly used in algo inits?
  (setf 
   note 
   (item 
    (intervals 
     7 2 0      ; would be nicer to us symbolic intervals here - how do i do
that?
     linked-to 'root)))
  (setf 
   rhythm  ; variations on a 7/8 rhythm
   (item      
     (rhythms 
      e.
      (rhythms 
       ((rhythms e. e e) min 4 max 4)  ; there's got to be a better way than
the mix/max
       ((rhythms e  e. e) min 4 max 4) ; bit. What I really want is to
choose a new subseq
       ((rhythms e e e.) min 4 max 4)  ; at a rythmic rate of E*7*2*2 = once
every 'root 
       in random for 1)                ; cycle (see 'root stream below). How
should I do that?
      e
      e)))))


;; The "Vulcan-Harp" part
(defun do-Vulcan-Harp (chan)
 (algorithm
  Vulcan-Harp pnote (
                     patch 'Vulcan-Harp
                     start 0 
                     channel chan
                     end (- opus-len 1)
                     duration (rhythm '32))
 (setf amplitude (item (amplitudes mp pp pp pp p pp pp)))  ; emphasize the
7/8 meter
 (setf rhythm (rhythm 'e))
 (setf 
  note
  (transpose
   (item 
    (intervals 0 5 10 linked-to 'root)) ; again, symbolic intervals would be
nicer - how?
   -12))))
   
     
;;; Now, ladies and gentlemen, whithout further adieu(sp?), here's the music!
;;; 
;;; One problem with this merge is that the 'root  item selection seems to
;;; happen *after* the item selections of the two threads, making the change
of root hapen
;;; after the beat instead of on it. What determines the order of evaluation
and how should
;;; I fix this problem?
(in-tempo 120 'q)    
(merge 
 merge-1 ()
 (mute ; "root-selector" sets the root note for the two defun'd algos below.
  root-selector (start 0 end opus-len rhythm (rhythm 'e*7*2)) ; 2 7/8
measures per root
  (item (notes c4 b3 named 'root))) ; thus, 4 7/8 measures per cycle
 ; The two parts for this creation:
 (do-Org400 1)        ; The argument is a MIDI channel #. Eventually it
would be nice
 (do-Vulcan-Harp 2))  ; to have a channel allocate/free setup. Any prior art
in this area?
     
;; the end