midi-message 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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