[CM] tempo change in midi files

Orm Finnendahl finnendahl@folkwang-hochschule.de
Mon, 17 Nov 2003 13:01:21 +0100

Hi Rick,

Am 16. November 2003, 17:10 Uhr (-0600) schrieb Rick Taube:
> another soulutino would be to define a seq that holds just your tempo 
> changes and then mix that into the file along with the output from your 
> musical processes:
> (new seq :name 'tpo :subobjects (make-tempo-map ...))
> (events (list #&tpo (my-piece)) "foo.midi")

Thanks for the hints. As you guessed, I was looking for a solution
which writes tempo messages into the file itself (in order to get rid
of my workaround doing it in the wait of the process loop). After
fiddling around with the sources and reading some of the cm-2.3 docs,
the mechanism becomes much clearer.

Two questions: 

1. Is there a straightforward way to keep time in musical time (from
   the beginning) rather than absolute time? Musical time should *not*
   be measured in beats, as the reference of the beats (denominator of
   time signature) might change. The format I formally (in cl) used
   were ratios expressing the musical time from the beginning in
   absolute values (like 1/4 or 127/8). The start of time signatures
   and tempo changes was expressed in the same format, put into
   separate sequences and mapped to the data prior to writing it to
   disk. As far as I understand, time in sequences of cm is expressed
   as absolute time and I fear that tempo-changes are taken into
   account in the events routine.

2. Taking your example above and applying that to time-signatures, I
   run into an error:

;; Definitions:

(define time-sig-list '((4 4) (7 8) (4 4)))

(define (make-time-sig-map timesiglist)
  (let ((curr 0))
     for x in timesiglist
     collect (new midimsg
                  :time curr
                  msg (apply #'make-time-signature x))
     do (set! curr (+ curr (apply #'/ x))))))

(new seq :name 'tmsig :subobjects (make-time-sig-map time-sig-list))

;; Tests:

(list-subobjects (find-object 'tmsig))

;; =>guile> ;;; Evaluate (list-subobjects (find-object 'tmsig))
;;   0. #i(midimsg time 0 msg #<values (11264 #(4 4 2 24 8))> data #f)
;;   1. #i(midimsg time 1 msg #<values (11264 #(4 7 3 24 8))> data #f)
;;   2. #i(midimsg time 1.875 msg #<values (11264 #(4 4 2 24 8))> data #f)
;;   guile> 

(events (list #&tmsig) "/tmp/foo.midi")

;; =>guile> ;;; Evaluate (events (list #&tmsig) "/tmp/foo.midi")
;; <unnamed port>: In procedure midi-write-message in expression (midi-write-message (midimsg-msg obj) mf ...):
;; <unnamed port>: No applicable method for #<<generic> midi-write-message (1)> in call (midi-write-message #<values (11264 #(4 4 2 24 8))> #<midi-file-stream "/tmp/foo.midi"> 0 #f)
;; ABORT: (goops-error)
;; guile>