Current section
Files
Jump to
Current section
Files
src/um/note.lfe
(defmodule um.note
(export all))
;;;;;;;;;;;;;
;;; PITCH ;;;
;;;;;;;;;;;;;
(defun G9 () 127 )
(defun F#9 () 126 )
(defun Gb9 () 126 )
(defun F9 () 125 )
(defun E9 () 124 )
(defun D#9 () 123 )
(defun Eb9 () 123 )
(defun D9 () 122 )
(defun C#9 () 121 )
(defun Db9 () 121 )
(defun C9 () 120 )
(defun B8 () 119 )
(defun A#8 () 118 )
(defun Bb8 () 118 )
(defun A8 () 117 )
(defun G#8 () 116 )
(defun Ab8 () 116 )
(defun G8 () 115 )
(defun F#8 () 114 )
(defun Gb8 () 114 )
(defun F8 () 113 )
(defun E8 () 112 )
(defun D#8 () 111 )
(defun Eb8 () 111 )
(defun D8 () 110 )
(defun C#8 () 109 )
(defun Db8 () 109 )
(defun C8 () 108 )
(defun B7 () 107 )
(defun A#7 () 106 )
(defun Bb7 () 106 )
(defun A7 () 105 )
(defun G#7 () 104 )
(defun Ab7 () 104 )
(defun G7 () 103 )
(defun F#7 () 102 )
(defun Gb7 () 102 )
(defun F7 () 101 )
(defun E7 () 100 )
(defun D#7 () 99 )
(defun Eb7 () 99 )
(defun D7 () 98 )
(defun C#7 () 97 )
(defun Db7 () 97 )
(defun C7 () 96 )
(defun B6 () 95 )
(defun A#6 () 94 )
(defun Bb6 () 94 )
(defun A6 () 93 )
(defun G#6 () 92 )
(defun Ab6 () 92 )
(defun G6 () 91 )
(defun F#6 () 90 )
(defun Gb6 () 90 )
(defun F6 () 89 )
(defun E6 () 88 )
(defun D#6 () 87 )
(defun Eb6 () 87 )
(defun D6 () 86 )
(defun C#6 () 85 )
(defun Db6 () 85 )
(defun C6 () 84 )
(defun B5 () 83 )
(defun A#5 () 82 )
(defun Bb5 () 82 )
(defun A5 () 81 )
(defun G#5 () 80 )
(defun Ab5 () 80 )
(defun G5 () 79 )
(defun F#5 () 78 )
(defun Gb5 () 78 )
(defun F5 () 77 )
(defun E5 () 76 )
(defun D#5 () 75 )
(defun Eb5 () 75 )
(defun D5 () 74 )
(defun C#5 () 73 )
(defun Db5 () 73 )
(defun C5 () 72 )
(defun B4 () 71 )
(defun A#4 () 70 )
(defun Bb4 () 70 )
(defun A4 () 69 )
(defun G#4 () 68 )
(defun Ab4 () 68 )
(defun G4 () 67 )
(defun F#4 () 66 )
(defun Gb4 () 66 )
(defun F4 () 65 )
(defun E4 () 64 )
(defun D#4 () 63 )
(defun Eb4 () 63 )
(defun D4 () 62 )
(defun C#4 () 61 )
(defun Db4 () 61 )
(defun C4 () 60 )
(defun B3 () 59 )
(defun A#3 () 58 )
(defun Bb3 () 58 )
(defun A3 () 57 )
(defun G#3 () 56 )
(defun Ab3 () 56 )
(defun G3 () 55 )
(defun F#3 () 54 )
(defun Gb3 () 54 )
(defun F3 () 53 )
(defun E3 () 52 )
(defun D#3 () 51 )
(defun Eb3 () 51 )
(defun D3 () 50 )
(defun C#3 () 49 )
(defun Db3 () 49 )
(defun C3 () 48 )
(defun B2 () 47 )
(defun A#2 () 46 )
(defun Bb2 () 46 )
(defun A2 () 45 )
(defun G#2 () 44 )
(defun Ab2 () 44 )
(defun G2 () 43 )
(defun F#2 () 42 )
(defun Gb2 () 42 )
(defun F2 () 41 )
(defun E2 () 40 )
(defun D#2 () 39 )
(defun Eb2 () 39 )
(defun D2 () 38 )
(defun C#2 () 37 )
(defun Db2 () 37 )
(defun C2 () 36 )
(defun B1 () 35 )
(defun A#1 () 34 )
(defun Bb1 () 34 )
(defun A1 () 33 )
(defun G#1 () 32 )
(defun Ab1 () 32 )
(defun G1 () 31 )
(defun F#1 () 30 )
(defun Gb1 () 30 )
(defun F1 () 29 )
(defun E1 () 28 )
(defun D#1 () 27 )
(defun Eb1 () 27 )
(defun D1 () 26 )
(defun C#1 () 25 )
(defun Db1 () 25 )
(defun C1 () 24 )
(defun B0 () 23 )
(defun A#0 () 22 )
(defun Bb0 () 22 )
(defun A0 () 21 )
(defun G#0 () 20 )
(defun Ab0 () 20 )
(defun G0 () 19 )
(defun F#0 () 18 )
(defun Gb0 () 18 )
(defun F0 () 17 )
(defun E0 () 16 )
(defun D#0 () 15 )
(defun Eb0 () 15 )
(defun D0 () 14 )
(defun C#0 () 13 )
(defun Db0 () 13 )
(defun C0 () 12 )
(defun B-1 () 11 )
(defun A#-1 () 10 )
(defun Bb-1 () 10 )
(defun A-1 () 9 )
(defun G#-1 () 8 )
(defun Ab-1 () 8 )
(defun G-1 () 7 )
(defun F#-1 () 6 )
(defun Gb-1 () 6 )
(defun F-1 () 5 )
(defun E-1 () 4 )
(defun D#-1 () 3 )
(defun Eb-1 () 3 )
(defun D-1 () 2 )
(defun C#-1 () 1 )
(defun Db-1 () 1 )
(defun C-1 () 0 )
(defun midi-names ()
#m(
G9 127
F#9 126
Gb9 126
F9 125
E9 124
D#9 123
Eb9 123
D9 122
C#9 121
Db9 121
C9 120
B8 119
A#8 118
Bb8 118
A8 117
G#8 116
Ab8 116
G8 115
F#8 114
Gb8 114
F8 113
E8 112
D#8 111
Eb8 111
D8 110
C#8 109
Db8 109
C8 108
B7 107
A#7 106
Bb7 106
A7 105
G#7 104
Ab7 104
G7 103
F#7 102
Gb7 102
F7 101
E7 100
D#7 99
Eb7 99
D7 98
C#7 97
Db7 97
C7 96
B6 95
A#6 94
Bb6 94
A6 93
G#6 92
Ab6 92
G6 91
F#6 90
Gb6 90
F6 89
E6 88
D#6 87
Eb6 87
D6 86
C#6 85
Db6 85
C6 84
B5 83
A#5 82
Bb5 82
A5 81
G#5 80
Ab5 80
G5 79
F#5 78
Gb5 78
F5 77
E5 76
D#5 75
Eb5 75
D5 74
C#5 73
Db5 73
C5 72
B4 71
A#4 70
Bb4 70
A4 69
G#4 68
Ab4 68
G4 67
F#4 66
Gb4 66
F4 65
E4 64
D#4 63
Eb4 63
D4 62
C#4 61
Db4 61
C4 60
B3 59
A#3 58
Bb3 58
A3 57
G#3 56
Ab3 56
G3 55
F#3 54
Gb3 54
F3 53
E3 52
D#3 51
Eb3 51
D3 50
C#3 49
Db3 49
C3 48
B2 47
A#2 46
Bb2 46
A2 45
G#2 44
Ab2 44
G2 43
F#2 42
Gb2 42
F2 41
E2 40
D#2 39
Eb2 39
D2 38
C#2 37
Db2 37
C2 36
B1 35
A#1 34
Bb1 34
A1 33
G#1 32
Ab1 32
G1 31
F#1 30
Gb1 30
F1 29
E1 28
D#1 27
Eb1 27
D1 26
C#1 25
Db1 25
C1 24
B0 23
A#0 22
Bb0 22
A0 21
G#0 20
Ab0 20
G0 19
F#0 18
Gb0 18
F0 17
E0 16
D#0 15
Eb0 15
D0 14
C#0 13
Db0 13
C0 12
B-1 11
B 11
A#-1 10
Bb-1 10
A# 10
Bb 10
A-1 9
A 9
G#-1 8
Ab-1 8
G# 8
Ab 8
G-1 7
G 7
F#-1 6
Gb-1 6
F# 6
Gb 6
F-1 5
F 5
E-1 4
E 4
D#-1 3
Eb-1 3
D# 3
Eb 3
D-1 2
D 2
C#-1 1
Db-1 1
C# 1
Db 1
C-1 0
C 0
))
(defun get-pitch (name)
(mref (midi-names) name))
(defun get-pitches (names)
(let ((all (midi-names)))
(list-comp ((<- n names))
(mref all n))))
(defun make
((names) (when (is_list names))
(list-comp ((<- n names)) (make n)))
((name)
(make name (get-velocity 'mp))))
(defun make (name velocity)
(make name velocity 100))
(defun make (name velocity duration)
(make name velocity duration 0))
(defun make
((name velocity duration delay) (when (is_atom name))
(make (get-pitch name) velocity duration delay))
((pitch velocity duration delay)
`#m(pitch ,pitch
velocity ,velocity
duration ,duration
delay ,delay)))
(defun make-fuzzy
((names) (when (is_list names))
(list-comp ((<- n names)) (make-fuzzy n)))
((n-or-p)
(make-fuzzy n-or-p (default-values))))
(defun make-fuzzy (n-or-p vals)
(make-fuzzy n-or-p vals (default-variances)))
(defun make-fuzzy
((name vals variances) (when (is_atom name))
(make-fuzzy (get-pitch name) vals variances))
((pitch values variances)
(let ((`#m(velocity ,v duration ,dur delay ,del)
(maps:merge (default-values) values))
(`#m(velocity ,v-var duration ,dur-var delay ,del-var)
(maps:merge (default-variances) variances)))
`#m(pitch ,pitch
velocity ,(fuzzy-velocity v v-var)
duration ,(fuzzy-duration dur dur-var)
delay ,(fuzzy-delay del del-var)))))
(defun default-values ()
`#m(velocity ,(get-velocity 'mp)
duration 100
delay 0))
(defun default-variances ()
#m(velocity 2
duration 2
delay 150))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; NOTE VALUE, DURATION & DELAY (before playing) ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun values ()
'(2 ; double note / breve
1 ; whole note / semibreve
1/2 ; half note / minim
1/4 ; quarter note / crotchet
1/8 ; eighth note / quaver
1/16 ; sixteenth note / semiquaver
1/32 ; thirty-second note / demisemiquaver
1/64 ; sixty-fourth note / hemidemisemiquaver
1/128 ; semihemidemisemiquaver
))
(defun value-multipliers ()
`#m(;; notes
(n 1.0)
(n. 1.5)
(n.. 1.75)
(n... 1.875)
;; rests
(r 1.0)
(r. 1.5)
(r.. 1.75)
(r... 1.875)))
(defun fuzzy-duration (ms)
(fuzzy-duration ms (mref (default-variances) 'duration)))
(defun fuzzy-duration (ms variance)
(round (abs (rand:normal ms variance))))
(defun fuzzy-delay (ms)
(fuzzy-delay ms (mref (default-variances) 'delay)))
(defun fuzzy-delay (ms variance)
(round (abs (rand:normal ms variance))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; DYNAMICS & VELOCITY ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
#| The initial division of the range 0-127 into the ppp to fff dynamic ranges
(of which there are eight) was done in the following manner:
lfe> (list-comp ((<- x (lutil-lists:chunks (lists:seq 10 120)
8 ; <-- number of parts
#(by-parts))))
(lists:nth 7 x))
Which gave:
(16 30 44 58 72 86 100 114)
Note that these may be changed to taste/hearing at a latter date.
|#
(defun dynamics ()
'(#(ffff 127)
#(fff 114) ; Fortississimo
#(ff 100) ; Fortissimo
#(f 86) ; Forte
#(mf 72) ; Mezzo forte
#(mp 58) ; Mezzo piano
#(p 44) ; Piano
#(pp 30) ; Pianissimo
#(ppp 16) ; Pianississimo
#(pppp 1)))
(defun velocities ()
(list-comp ((<- `#(,k ,v) (dynamics))) `#(,v ,k)))
(defun get-velocity (name)
(proplists:get_value name (dynamics)))
(defun get-dynamic (num)
(proplists:get_value num (velocities)))
#| To get the MIDI ranges for the dynamics, did the following in the LFE REPL:
lfe> (lfe_io:format "~w~n" (list (lists:reverse (++ '(127)
(cdr
(lists:flatten
(lists:map (match-lambda ((`(,a ,b))
(let ((range (round (/ (- a b) 2))))
(list (+ a range) (- a range)))))
(lutil-list:chunks vs 2 #(by-length)))))))))
Which gave:
(8 24 37 51 65 79 93 107 120 127)
|#
(defun nearest-dynamic
((num) (when (=< num 8))
'pppp)
((num) (when (=< num 24))
'ppp)
((num) (when (=< num 37))
'pp)
((num) (when (=< num 51))
'p)
((num) (when (=< num 65))
'mp)
((num) (when (=< num 79))
'mf)
((num) (when (=< num 93))
'f)
((num) (when (=< num 107))
'ff)
((num) (when (=< num 120))
'fff)
((num) (when (> num 120))
'ffff))
#| It seems like a normal distribution around a dynamic would be a nice first-
approximation for selecting a random velocity that stays within the defined
range of a given dynamic.
|#
(defun fuzzy-velocity (name)
(fuzzy-velocity name (mref (default-variances) 'velocity)))
(defun fuzzy-velocity
((name variance) (when (is_atom name))
(fuzzy-velocity (get-velocity name) variance))
((v variance)
(round (abs (rand:normal v variance)))))
;;;;;;;;;;;;;;;;;;;
;;; PERFORMANCE ;;;
;;;;;;;;;;;;;;;;;;;
(defun play
((device channel notes) (when (is_list notes))
(play-notes device channel notes))
((device channel note) (when (is_map note))
(play-note device channel note)))
(defun play-note
((device channel note) (when (is_atom note))
(play-note device channel (make note)))
((device channel `#m(pitch ,p velocity ,v duration ,dur delay ,del))
(let ((note-on (midimsg:note-on channel p v))
(note-off (midimsg:note-on channel p 0)))
(timer:apply_after del 'um.ml 'send `(,device ,note-on))
(timer:apply_after (- dur del) 'um.ml 'send `(,device ,note-off)))))
(defun play-notes (device channel notes)
(play-notes device channel notes 250))
(defun play-notes (device channel notes delay)
(play-notes device channel notes delay 0))
(defun play-notes (device channel notes delay repeats)
(play-notes device channel notes delay repeats '()))
(defun play-notes
((device channel '() _ 0 _)
'ok)
((device channel '() delay repeats acc)
(play-notes device channel acc delay (- repeats 1) '()))
((device channel `(,head . ,tail) delay repeats acc)
(play-note device channel head)
;; 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))
(defun delay (notes delay-multiplier)
(lists:map (lambda (m)
(mset m 'delay (* delay-multiplier (mref m 'delay))))
notes))