;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PLAYP - PlayPattern function - like a step sequencer
;
; Prerequisites:
; - `beat` and `dur` symbols bound in outer function
; - symbol `*mididevice*` MAPPED TO AN OUTPUT STREAM
;
; Signature:
; playp N:ch N:bars [opt:N:durOffset] [opt:N:pOffset] ():pattern ():vols [opt:N:dur]
;
; Args:
; - channel (1-based)
; - cycle-dur
; - offset [default = 0]
; - poffset [default = 0]
; - plist
; - vol
; - dur [default = cycle / len(plist) * 0.9]
;
; Adapted from original implementation in Extempore: https://github.com/digego/extempore/tree/v0.8.9/libs/external/portmidi.xtm
;
; Main changes:
; - defaults to MIDI play (mplay)
; - channel is 1-based
; - pitch duration can be omitted as it's inferred from loop duration
; - function signature slightly altered
;
; Notes:
; - Contrary to the original mplayp implementation, CYCLE argument is always required, ie it does not get inferred from dur
; - The first arg must always be cycle-dur, then notes-list, etc... (in original implementation, mididevide/closure was used as a delimiter)
; - Due to args order, a poffset can be passed only after an offset, so set offset to 0 if all you need is a poffset
;
;
; Example:
; (define *mididevice* (pm_create_output_stream 1))
; (define piano 1) ; =midi channel
; (define playp-test
; (lambda (beat)
; (let ((dur 1/16))
; (playp piano 4 '(60 72) 60)
; (playp piano 2 1/4 (oneof 5 7) (list 60 72) 60) ;; random poffset changes the pitch
; (callback (*metro* (+ beat (* 1/2 dur)))
; 'gg (+ beat dur)))))
;
; (playp-test (*metro* 'get-beat 1))
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(impc:aot:do-or-emit
(define-macro (playp . args)
`(helper:mmplayp_f_with_offset beat dur *mididevice* ,@args))
)