d@34
|
1 (cl:in-package #:amuse-midi)
|
d@34
|
2
|
d@34
|
3 (defgeneric midi-channel (midi-message))
|
d@34
|
4 (defmethod midi-channel ((midi-message midi-message))
|
d@34
|
5 (%midi-message-channel midi-message))
|
d@34
|
6
|
d@34
|
7 (defgeneric midi-track (midi-message))
|
d@34
|
8 (defmethod midi-track ((midi-message midi-message))
|
d@34
|
9 (%midi-message-track midi-message))
|
d@34
|
10
|
d@34
|
11 (defgeneric midi-velocity (event))
|
d@34
|
12 (defmethod midi-velocity ((event midi-pitched-event))
|
d@34
|
13 (%midi-pitched-event-velocity event))
|
d@34
|
14 (defmethod midi-velocity ((event midi-percussive-event))
|
d@34
|
15 (%midi-percussive-event-velocity event))
|
d@34
|
16
|
d@34
|
17 (defgeneric midi-patch (event))
|
d@34
|
18 (defmethod midi-patch ((event midi-pitched-event))
|
d@34
|
19 (%midi-pitched-event-patch event))
|
d@34
|
20
|
d@34
|
21 (defgeneric midi-drum-sound (event))
|
d@34
|
22 (defmethod midi-drum-sound ((event midi-percussive-event))
|
d@34
|
23 (%midi-percussive-event-sound event))
|
d@34
|
24
|
d@34
|
25 (defmethod time-signatures ((composition midi-composition))
|
d@34
|
26 (%midi-time-signatures composition))
|
d@34
|
27 (defmethod (setf time-signatures) (sequence (composition midi-composition))
|
d@34
|
28 (setf (%midi-time-signatures composition) sequence))
|
d@34
|
29 (defmethod tempi ((composition midi-composition))
|
d@34
|
30 (%midi-tempi composition))
|
d@34
|
31 (defmethod (setf tempi) (sequence (composition midi-composition))
|
d@34
|
32 (setf (%midi-tempi composition) sequence))
|
d@34
|
33
|
d@34
|
34 (defgeneric copy-event (event))
|
d@34
|
35 ;; FIXME: This ought to call-next-method and operate on the result,
|
d@34
|
36 ;; rather than calling internals from the other package
|
d@34
|
37 (defmethod copy-event ((event midi-pitched-event))
|
d@34
|
38 (with-slots (channel track (number amuse::number) (time amuse::time) (interval amuse::interval) velocity patch)
|
d@34
|
39 event
|
d@34
|
40 (make-instance 'midi-pitched-event
|
d@34
|
41 :channel channel
|
d@34
|
42 :track track
|
d@34
|
43 :number number
|
d@34
|
44 :time time
|
d@34
|
45 :interval interval
|
d@34
|
46 :velocity velocity
|
d@34
|
47 :patch patch)))
|
d@34
|
48 (defmethod copy-event ((event midi-percussive-event))
|
d@34
|
49 (with-slots (channel track (time amuse::time) (interval amuse::interval) velocity patch sound)
|
d@34
|
50 event
|
d@34
|
51 (make-instance 'midi-percussive-event
|
d@34
|
52 :channel channel
|
d@34
|
53 :track track
|
d@34
|
54 :time time
|
d@34
|
55 :interval interval
|
d@34
|
56 :velocity velocity
|
d@34
|
57 :patch patch
|
d@34
|
58 :sound sound)))
|
d@34
|
59
|
d@34
|
60
|
d@34
|
61 ;; Allow derived sequences from remove-if, etc. to preserve other slot
|
d@34
|
62 ;; info (timesigs, etc)
|
d@34
|
63 (defmethod sequence:make-sequence-like :around ((o midi-composition) length
|
d@34
|
64 &key (initial-element nil iep)
|
d@34
|
65 (initial-contents nil icp))
|
d@34
|
66 (declare (ignore length initial-element initial-contents))
|
d@34
|
67 (let ((result (call-next-method)))
|
d@34
|
68 (cond
|
d@34
|
69 ((or iep icp)
|
d@34
|
70 (setf (timepoint result) (timepoint (elt result 0))
|
d@34
|
71 (duration result) (- (timepoint
|
d@34
|
72 (loop for e being the elements of result
|
d@34
|
73 maximize (cut-off e)))
|
d@34
|
74 (timepoint (elt result 0)))))
|
d@34
|
75 (t (setf (timepoint result) 0
|
d@34
|
76 (duration result) 0)))
|
d@34
|
77 (with-slots (time-signatures tempi misc-controllers)
|
d@34
|
78 o
|
d@34
|
79 (setf (%midi-time-signatures result) time-signatures
|
d@34
|
80 (%midi-tempi result) tempi
|
d@34
|
81 (%midi-misc-controllers result) misc-controllers))
|
d@34
|
82 result))
|
d@34
|
83
|
d@34
|
84
|
d@34
|
85 ;; useful little function
|
d@34
|
86
|
d@34
|
87 (defun microsecond-per-crotchet-to-bpm (mu-per-c)
|
d@34
|
88 (/ 60000000 mu-per-c))
|
d@34
|
89
|
d@34
|
90 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
d@34
|
91 ;;
|
d@34
|
92 ;; MIDI playback methods
|
d@34
|
93
|
d@34
|
94 (defmethod get-patch-for-midi ((event midi-pitched-event))
|
d@34
|
95 ;; FIXME
|
d@34
|
96 (midi-patch event))
|
d@34
|
97
|
d@34
|
98 (defmethod get-channel-for-midi ((event midi-message))
|
d@34
|
99 ;; FIXME 1- ??? I'm only doing this because of the Geerdes
|
d@34
|
100 ;; database. Looks like a recipe for disaster. Think should probably
|
d@34
|
101 ;; enforce 0-15.
|
d@34
|
102 (1- (midi-channel event)))
|
d@34
|
103
|
d@34
|
104 (defmethod get-velocity-for-midi ((event midi-message))
|
d@34
|
105 ;; FIXME: under-exclusive specialisation. Does this matter?
|
d@34
|
106 (midi-velocity event))
|
d@34
|
107
|
d@34
|
108 (defmethod get-pitch-for-midi ((event midi-percussive-event))
|
d@34
|
109 (midi-drum-sound event))
|
d@34
|
110
|
d@34
|
111 (defmethod get-pitch-for-midi ((event midi-pitched-event))
|
d@41
|
112 (midi-pitch-number event))
|
d@41
|
113
|
d@41
|
114 ;; Have avoided percussion vs pitched, as this is more obviously
|
d@41
|
115 ;; meaningless.
|
d@41
|
116 (defmethod significantly-louderp ((event1 midi-pitched-event) (event2 midi-pitched-event))
|
d@41
|
117 (>= (/ (midi-velocity event1)
|
d@41
|
118 (midi-velocity event2))
|
d@41
|
119 4/3))
|
d@41
|
120 (defmethod significantly-louderp ((event1 midi-percussive-event) (event2 midi-percussive-event))
|
d@41
|
121 (>= (/ (midi-velocity event1)
|
d@41
|
122 (midi-velocity event2))
|
d@41
|
123 4/3))
|
d@41
|
124 (defmethod substantially-louderp ((event1 midi-pitched-event) (event2 midi-pitched-event))
|
d@41
|
125 (>= (/ (midi-velocity event1)
|
d@41
|
126 (midi-velocity event2))
|
d@41
|
127 2))
|
d@41
|
128 (defmethod substantially-louderp ((event1 midi-percussive-event) (event2 midi-percussive-event))
|
d@41
|
129 (>= (/ (midi-velocity event1)
|
d@41
|
130 (midi-velocity event2))
|
d@41
|
131 2))
|
d@114
|
132
|
d@114
|
133 (defmethod crotchet ((event midi-message))
|
d@114
|
134 (make-instance 'floating-period :interval 1))
|
d@114
|
135
|
d@114
|
136 (defmethod crotchet ((composition midi-composition))
|
d@114
|
137 (make-instance 'floating-period :interval 1))
|
d@114
|
138
|
d@114
|
139 (defmethod crotchet ((identifier midifile-identifier))
|
d@114
|
140 (make-instance 'floating-period :interval 1)) |