Skip to content

Commit

Permalink
Worked on chord support.
Browse files Browse the repository at this point in the history
  • Loading branch information
oubiwann committed Sep 21, 2024
1 parent 74888d8 commit fcb2700
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 19 deletions.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Note that, depending upon the configured log level, you may see a fair amount of

``` lisp
(undermidi:start)
(um:list-devices)
(undermidi:list-devices)
(set device "model_15")
(set channel 1)
(set term (midimsg:note-on channel 48 64))
Expand All @@ -60,13 +60,13 @@ Note that, depending upon the configured log level, you may see a fair amount of
(um.ml:send device term)
(undermidi:start)
(um:list-devices)
(undermidi:list-devices)
(set device "model_15")
(set channel 1)
(um.note:play device channel (um.note:make 'C3))
(undermidi:start)
(um:list-devices)
(undermidi:list-devices)
(set device "model_15")
(set channel 1)
(um.note:play-notes device channel (um.note:make '(C3 C3 C4 C3)) 500)
Expand All @@ -76,7 +76,7 @@ Note that, depending upon the configured log level, you may see a fair amount of
(um.note:play-notes device channel notes 250 8)
(undermidi:start)
(um:list-devices)
(undermidi:list-devices)
(set device "model_15")
(set `#(ok ,d) (undermidi.devices:new device))
(undermidi.device.conn:echo d "testing ...")
Expand All @@ -87,6 +87,25 @@ Note that, depending upon the configured log level, you may see a fair amount of
(undermidi:play-notes d '(seq-1b) 250 8)
(undermidi:play-notes d '(seq-2a) 250 8)
(undermidi:play-notes d '(seq-3a) 250 8)
(undermidi:start)
(undermidi:list-devices)
(set device "midi_bus_1")
(set device "provs-mini_provs-mini_midi_1_24_0")
(set `#(ok ,d) (undermidi.devices:new device))
(include-lib "priv/seqs/basic.lfe")
(set notes (um.note:legnthen (um.chord:make-fuzzy (seq-3a) 80)))
(undermidi:play-notes d notes 8200 1)
(undermidi:start)
(set device "midi_bus_1")
(set `#(ok ,d) (undermidi.devices:new device))
(set cmaj7 (um.chord:lengthen (um.chord:make-fuzzy '(C4 E4 G4 B4)) 40))
(set am7 (um.chord:lengthen (um.chord:make-fuzzy '(C4 E4 G4 A4)) 40))
(set fmaj7 (um.chord:lengthen (um.chord:make-fuzzy '(C4 E4 F4 A4)) 40))
(set dm7 (um.chord:lengthen (um.chord:make-fuzzy '(C4 D4 F4 A4)) 40))
(set bdim7 (um.chord:lengthen (um.chord:make-fuzzy '(B3 D4 F4 A4)) 40))
(undermidi:play-chords d (list cmaj7 am7 fmaj7 dm7 bdim7) 4200 0)
```

## API
Expand Down
46 changes: 40 additions & 6 deletions src/um/chord.lfe
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,47 @@

(include-lib "logjam/include/logjam.hrl")

(defun make (notes)
'tbd)

(defun make (names)
(um.note:make names))

(defun make-fuzzy (names)
(um.note:make-fuzzy names))

(defun invert
((`(#m(pitch ,p velocity ,v duration ,d) . ,tail))
(++ tail (list (um.note:make (+ 12 p) v d)))))

(defun play ()
'tbd)

(defun play
((device channel '())
'ok)
((device channel (= `(,head . ,_) notes)) (when (is_atom head))
(play device channel (um.note:make notes)))
((device channel `(#m(pitch ,p velocity ,v duration ,d) . ,tail))
(let ((note-on (midimsg:note-on channel p v))
(note-off (midimsg:note-on channel p 0)))
(um.ml:send device note-on)
(timer:apply_after d 'um.ml 'send `(,device ,note-off))
(play device channel tail))))

(defun play-chords (device channel chords)
(play-chords device channel chords 250))

(defun play-chords (device channel chords delay)
(play-chords device channel chords delay 0))

(defun play-chords (device channel chords delay repeats)
(play-chords device channel chords delay repeats '()))

(defun play-chords
((device channel '() _ 0 _)
'ok)
((device channel '() delay repeats acc)
(play-chords device channel acc delay (- repeats 1) '()))
((device channel `(,head . ,tail) delay repeats acc)
(play device channel head)
;; TODO: this is a hack; we need to send timing data MIDI messages ...
(timer:sleep delay)
(play-chords device channel tail delay repeats (++ acc `(,head)))))

(defun lengthen (chord duration-multiplier)
(um.note:lengthen chord duration-multiplier))
5 changes: 5 additions & 0 deletions src/um/note.lfe
Original file line number Diff line number Diff line change
Expand Up @@ -549,3 +549,8 @@ range of a given dynamic.
;; TODO: this is a hack; we need to send timing data MIDI messages ...
(timer:sleep delay)
(play-notes device channel tail delay repeats (++ acc `(,head)))))

(defun lengthen (notes duration-multiplier)
(lists:map (lambda (m)
(mset m 'duration (* duration-multiplier (mref m 'duration))))
notes))
57 changes: 48 additions & 9 deletions src/undermidi.lfe
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
(export
(play-note 2)
(play-notes 2) (play-notes 3) (play-notes 4)
(play-chord 2)
(play-chords 2) (play-chords 3) (play-chords 4)
)
(export
(list-devices 0)
Expand Down Expand Up @@ -43,32 +45,40 @@
(io:format " ~p. ~s~n" (list index name)))
'ok)

;;; The following functions define an API for a gen_server that manages the
;;; state of individual "connections" to MIDI devices. Due to the state
;;; management of the gen_server, neither device name nore channel are passed
;;; in these functions. If a more functional approach is desired, then the
;;; developer should access directly the various functions that are wrapped
;;; here.
;;; The following functions define an API that wraps functions of the gen_server
;;; that manages the state of individual "connections" to MIDI devices. Due to
;;; the state management of the gen_server, neither device name nore channel are
;;; passed in these functions. If a more functional approach is desired, then the
;;; developer should access directly the various functions that are wrapped here.

;; Notes API

(defun play-note
((pid note) (when (is_atom note))
(play-note pid (um.note:make note)))
((pid note)
(undermidi.device.conn:apply pid 'um.note 'play-note (list note))))
(undermidi.device.conn:apply pid
'um.note
'play-note
(list note))))

(defun play-notes
((pid (= `(,head . ,_) notes)) (when (is_atom head))
(play-notes pid (um.note:make notes)))
((pid notes)
(undermidi.device.conn:apply pid 'um.note 'play-notes (list notes))))
(undermidi.device.conn:apply pid
'um.note
'play-notes
(list notes))))

(defun play-notes
((pid (= `(,head . ,_) notes) delay) (when (is_atom head))
(play-notes pid (um.note:make notes) delay))
((pid notes delay)
(undermidi.device.conn:apply pid 'um.note 'play-notes (list notes delay))))
(undermidi.device.conn:apply pid
'um.note
'play-notes
(list notes delay))))

(defun play-notes
((pid (= `(,head . ,_) notes) delay repeats) (when (is_atom head))
Expand All @@ -79,6 +89,35 @@
'play-notes
(list notes delay repeats))))

;; Chords API

(defun play-chord
((pid (= `(,head . ,_) notes)) (when (is_atom head))
(play-chord pid (um.chord:make notes)))
((pid chord)
(undermidi.device.conn:apply pid
'um.chord
'play
(list chord))))

(defun play-chords (pid chords)
(undermidi.device.conn:apply pid
'um.chord
'play-chords
(list chords)))

(defun play-chords (pid chords delay)
(undermidi.device.conn:apply pid
'um.chord
'play-chords
(list chords delay)))

(defun play-chords (pid chords delay repeats)
(undermidi.device.conn:apply pid
'um.chord
'play-chords
(list chords delay repeats)))

;;; Aliases

(defun version ()
Expand Down

0 comments on commit fcb2700

Please sign in to comment.