midi-message 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,212 +1,53 @@
1
1
  module MIDIMessage
2
2
 
3
- #
4
- # MIDI Channel Aftertouch message
5
- #
6
- class ChannelAftertouch
7
-
8
- include ChannelMessage
9
-
10
- DATA = [:channel, :value]
11
- DISPLAY_NAME = "Channel Aftertouch"
12
-
13
- end
14
- ChannelPressure = ChannelAftertouch
15
-
16
- #
17
- # MIDI Control Change message
18
- #
19
- class ControlChange
20
-
21
- include ChannelMessage
22
-
23
- DATA = [:channel, :index, :value]
24
- DISPLAY_NAME = "Control Change"
25
- CONSTANT = { "Control Change" => :index }
26
-
27
- end
28
- Controller = ControlChange #shortcut
29
-
30
- #
31
- # MIDI Pitch Bend message
32
- #
33
- class PitchBend
34
-
35
- include ChannelMessage
36
-
37
- DATA = [:channel, :low, :high]
38
- DISPLAY_NAME = "Pitch Bend"
39
-
40
- end
41
-
42
- #
43
- # MIDI Polyphonic (note specific) Aftertouch message
44
- #
45
- class PolyphonicAftertouch
46
-
47
- include ChannelMessage
48
-
49
- DATA = [:channel, :note, :value]
50
- DISPLAY_NAME = "Polyphonic Aftertouch"
51
- CONSTANT = { "Note" => :note }
52
-
53
- end
54
- PolyAftertouch = PolyphonicAftertouch
55
- PolyPressure = PolyphonicAftertouch
56
- PolyphonicPressure = PolyphonicAftertouch
57
-
58
- #
59
- # MIDI Program Change message
60
- #
61
- class ProgramChange
62
-
63
- include ChannelMessage
64
-
65
- DATA = [:channel, :program]
66
- DISPLAY_NAME = "Program Change"
67
-
68
- end
69
-
70
- #
71
- # MIDI Note-Off message
72
- #
73
- class NoteOff
74
-
75
- include NoteMessage
76
-
77
- DATA = [:channel, :note, :velocity]
78
- DISPLAY_NAME = "Note Off"
79
- CONSTANT = { "Note" => :note }
80
-
81
- end
82
-
83
- #
84
- # MIDI Note-On message
85
- #
86
- class NoteOn
87
-
88
- include NoteMessage
89
-
90
- DATA = [:channel, :note, :velocity]
91
- DISPLAY_NAME = "Note On"
92
- CONSTANT = { "Note" => :note }
93
-
94
- # returns the NoteOff equivalent of this object
95
- def to_note_off
96
- NoteOff.new(channel, note, velocity)
3
+ # Common behavior amongst all Message types
4
+ module Message
5
+
6
+ # Initialize the message status
7
+ # @param [Fixnum] status_nibble_1 The first nibble of the status
8
+ # @param [Fixnum] status_nibble_2 The second nibble of the status
9
+ def initialize_message(status_nibble_1, status_nibble_2)
10
+ @status = [status_nibble_1, status_nibble_2]
11
+ populate_using_const
97
12
  end
98
13
 
99
- end
100
-
101
- #
102
- # MIDI System-Common message
103
- #
104
- class SystemCommon
105
-
106
- include SystemMessage
107
-
108
- DISPLAY_NAME = "System Common"
109
-
110
- attr_reader :data
111
-
112
- def initialize(*args)
113
- options = args.last.kind_of?(Hash) ? args.pop : {}
114
- @const = options[:const]
115
- id = @const.nil? ? args.shift : @const.value
116
- id = strip_redundant_nibble(id)
117
- initialize_short_message(0xF, id)
118
- @data = args.slice(0..1)
14
+ # Byte array representation of the message eg [0x90, 0x40, 0x40] for NoteOn(0x40, 0x40)
15
+ # @return [Array<Fixnum>] The array of bytes in the MIDI message
16
+ def to_a
17
+ data = @data.nil? ? [] : [@data[0], @data[1]]
18
+ [(@status[0] << 4) + @status[1], *data].compact
119
19
  end
120
-
121
- end
122
-
123
- #
124
- # MIDI System-Realtime message
125
- #
126
- class SystemRealtime
127
-
128
- include SystemMessage
129
-
130
- DISPLAY_NAME = "System Realtime"
131
-
132
- def initialize(*args)
133
- options = args.last.kind_of?(Hash) ? args.pop : {}
134
- @const = options[:const]
135
- id = @const.nil? ? args.first : @const.value
136
- id = strip_redundant_nibble(id)
137
- initialize_short_message(0xF, id)
20
+ alias_method :to_byte_a, :to_a
21
+ alias_method :to_byte_array, :to_a
22
+ alias_method :to_bytes, :to_a
23
+
24
+ # String representation of the message's bytes eg "904040" for NoteOn(0x40, 0x40)
25
+ # @return [String] The bytes of the message as a string of hex bytes
26
+ def to_hex_s
27
+ TypeConversion.numeric_byte_array_to_hex_string(to_a)
138
28
  end
29
+ alias_method :to_bytestr, :to_hex_s
139
30
 
140
- def id
141
- @status[1]
31
+ def update
32
+ populate_using_const
142
33
  end
143
34
 
144
- end
145
-
146
- module SystemExclusive
147
-
148
- # A SysEx command message
149
- # A command message is identified by having a status byte equal to 0x12
150
- class Command
151
-
152
- include SystemExclusive
153
-
154
- attr_accessor :data
155
- alias_method :value, :data
35
+ protected
156
36
 
157
- TypeByte = 0x12
158
-
159
- def initialize(address, data, options = {})
160
- # store as a byte if it's a single byte
161
- @data = if data.kind_of?(Array) && data.length == 1
162
- data.first
163
- else
164
- data
165
- end
166
- initialize_sysex(address, options)
37
+ def populate_using_const
38
+ unless (info = Constant::Loader.get_info(self)).nil?
39
+ @const = info[:const]
40
+ @name = info[:name]
41
+ @verbose_name = info[:verbose_name]
167
42
  end
168
-
169
43
  end
170
-
171
- # A SysEx request message
172
- # A request message is identified by having a status byte equal to 0x11
173
- class Request
174
44
 
175
- include SystemExclusive
176
-
177
- attr_reader :size
178
- alias_method :value, :size
179
-
180
- TypeByte = 0x11
181
-
182
- def initialize(address, size, options = {})
183
- self.size = if size.kind_of?(Array) && size.count == 1
184
- size.first
185
- else
186
- size
187
- end
188
- initialize_sysex(address, options)
189
- end
190
-
191
- def size=(value)
192
- # accepts a Numeric or Array but
193
- # must always store value as an array of three bytes
194
- size = []
195
- if value.kind_of?(Array) && value.size <= 3
196
- size = value
197
- elsif value.kind_of?(Numeric) && (value + 1) / 247 <= 2
198
- size = []
199
- div, mod = *value.divmod(247)
200
- size << mod unless mod.zero?
201
- div.times { size << 247 }
202
- end
203
- (3 - size.size).times { size.unshift 0 }
204
- @size = size
205
- end
206
-
45
+ def self.included(base)
46
+ base.send(:extend, Constant::Loader::DSL)
47
+ base.send(:include, MIDIMessage) # this enables ..kind_of?(MIDIMessage)
48
+ base.send(:attr_reader, :name, :status, :verbose_name)
207
49
  end
208
50
 
209
51
  end
210
-
211
- end
212
52
 
53
+ end
@@ -0,0 +1,211 @@
1
+ module MIDIMessage
2
+
3
+ #
4
+ # MIDI Channel Aftertouch message
5
+ #
6
+ class ChannelAftertouch
7
+
8
+ include ChannelMessage
9
+
10
+ DATA = [:channel, :value]
11
+ DISPLAY_NAME = "Channel Aftertouch"
12
+
13
+ end
14
+ ChannelPressure = ChannelAftertouch
15
+
16
+ #
17
+ # MIDI Control Change message
18
+ #
19
+ class ControlChange
20
+
21
+ include ChannelMessage
22
+
23
+ DATA = [:channel, :index, :value]
24
+ DISPLAY_NAME = "Control Change"
25
+ CONSTANT = { "Control Change" => :index }
26
+
27
+ end
28
+ Controller = ControlChange #shortcut
29
+
30
+ #
31
+ # MIDI Pitch Bend message
32
+ #
33
+ class PitchBend
34
+
35
+ include ChannelMessage
36
+
37
+ DATA = [:channel, :low, :high]
38
+ DISPLAY_NAME = "Pitch Bend"
39
+
40
+ end
41
+
42
+ #
43
+ # MIDI Polyphonic (note specific) Aftertouch message
44
+ #
45
+ class PolyphonicAftertouch
46
+
47
+ include ChannelMessage
48
+
49
+ DATA = [:channel, :note, :value]
50
+ DISPLAY_NAME = "Polyphonic Aftertouch"
51
+ CONSTANT = { "Note" => :note }
52
+
53
+ end
54
+ PolyAftertouch = PolyphonicAftertouch
55
+ PolyPressure = PolyphonicAftertouch
56
+ PolyphonicPressure = PolyphonicAftertouch
57
+
58
+ #
59
+ # MIDI Program Change message
60
+ #
61
+ class ProgramChange
62
+
63
+ include ChannelMessage
64
+
65
+ DATA = [:channel, :program]
66
+ DISPLAY_NAME = "Program Change"
67
+
68
+ end
69
+
70
+ #
71
+ # MIDI Note-Off message
72
+ #
73
+ class NoteOff
74
+
75
+ include NoteMessage
76
+
77
+ DATA = [:channel, :note, :velocity]
78
+ DISPLAY_NAME = "Note Off"
79
+ CONSTANT = { "Note" => :note }
80
+
81
+ end
82
+
83
+ #
84
+ # MIDI Note-On message
85
+ #
86
+ class NoteOn
87
+
88
+ include NoteMessage
89
+
90
+ DATA = [:channel, :note, :velocity]
91
+ DISPLAY_NAME = "Note On"
92
+ CONSTANT = { "Note" => :note }
93
+
94
+ # returns the NoteOff equivalent of this object
95
+ def to_note_off
96
+ NoteOff.new(channel, note, velocity)
97
+ end
98
+
99
+ end
100
+
101
+ #
102
+ # MIDI System-Common message
103
+ #
104
+ class SystemCommon
105
+
106
+ include SystemMessage
107
+
108
+ DISPLAY_NAME = "System Common"
109
+
110
+ attr_reader :data
111
+
112
+ def initialize(*args)
113
+ options = args.last.kind_of?(Hash) ? args.pop : {}
114
+ @const = options[:const]
115
+ id = @const.nil? ? args.shift : @const.value
116
+ id = strip_redundant_nibble(id)
117
+ initialize_message(0xF, id)
118
+ @data = args.slice(0..1)
119
+ end
120
+
121
+ end
122
+
123
+ #
124
+ # MIDI System-Realtime message
125
+ #
126
+ class SystemRealtime
127
+
128
+ include SystemMessage
129
+
130
+ DISPLAY_NAME = "System Realtime"
131
+
132
+ def initialize(*args)
133
+ options = args.last.kind_of?(Hash) ? args.pop : {}
134
+ @const = options[:const]
135
+ id = @const.nil? ? args.first : @const.value
136
+ id = strip_redundant_nibble(id)
137
+ initialize_message(0xF, id)
138
+ end
139
+
140
+ def id
141
+ @status[1]
142
+ end
143
+
144
+ end
145
+
146
+ module SystemExclusive
147
+
148
+ # A SysEx command message
149
+ # A command message is identified by having a status byte equal to 0x12
150
+ class Command
151
+
152
+ include SystemExclusive
153
+
154
+ attr_accessor :data
155
+ alias_method :value, :data
156
+
157
+ TypeByte = 0x12
158
+
159
+ def initialize(address, data, options = {})
160
+ # store as a byte if it's a single byte
161
+ @data = if data.kind_of?(Array) && data.length == 1
162
+ data.first
163
+ else
164
+ data
165
+ end
166
+ initialize_sysex(address, options)
167
+ end
168
+
169
+ end
170
+
171
+ # A SysEx request message
172
+ # A request message is identified by having a status byte equal to 0x11
173
+ class Request
174
+
175
+ include SystemExclusive
176
+
177
+ attr_reader :size
178
+ alias_method :value, :size
179
+
180
+ TypeByte = 0x11
181
+
182
+ def initialize(address, size, options = {})
183
+ self.size = if size.kind_of?(Array) && size.count == 1
184
+ size.first
185
+ else
186
+ size
187
+ end
188
+ initialize_sysex(address, options)
189
+ end
190
+
191
+ def size=(value)
192
+ # accepts a Numeric or Array but
193
+ # must always store value as an array of three bytes
194
+ size = []
195
+ if value.kind_of?(Array) && value.size <= 3
196
+ size = value
197
+ elsif value.kind_of?(Numeric) && (value + 1) / 247 <= 2
198
+ size = []
199
+ div, mod = *value.divmod(247)
200
+ size << mod unless mod.zero?
201
+ div.times { size << 247 }
202
+ end
203
+ (3 - size.size).times { size.unshift 0 }
204
+ @size = size
205
+ end
206
+
207
+ end
208
+
209
+ end
210
+
211
+ end