midi-message 0.4.1 → 0.4.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad978e231aef5931892a5fb96573c4e709f3ad64
4
- data.tar.gz: 53cc976f50cb5c4d5ba619f3d3d4b1aaa10a71d9
3
+ metadata.gz: 539a68753cc6d0c17fed06cae7103d1f7b0f95a8
4
+ data.tar.gz: 2b3949261e5e5fa7061cb7860c325d6a0c067efb
5
5
  SHA512:
6
- metadata.gz: 6a51573df46bbee8bc764be4d139b52c7366c192c0402846bb3cae67efa4e5cbfa87b4ad1982765fc80f2d6d3e088c857f6ee5a9b0bc6d0f68a2e2ca08f3a931
7
- data.tar.gz: c7264a018b5b523aeaa7391ab2f387aab0a2a9b66f583692bdd05a12eb7968c9ebc0ef120de61cfe82ab42e6f8c3301522fe957f6fc9ca9b5969d387ff8f1c5c
6
+ metadata.gz: edc31730d5ffc918377fb342f63c3ce095b187e8f17ed194a47756a701286f3a78b7d7102f05850a2eeca59108d90ec3ed1a9cb5e0e78294cea699c6ede821b6
7
+ data.tar.gz: 86c8b7a355baa3a46d93ca63294a512538dc8478fbea9844be00c917916fe1d13fde7bd19eb599a2cf61fefff021df45f853a43622d6bb8380322f03136e6e30
data/lib/midi-message.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  #
6
6
  module MIDIMessage
7
7
 
8
- VERSION = "0.4.1"
8
+ VERSION = "0.4.2"
9
9
 
10
10
  end
11
11
 
@@ -46,8 +46,8 @@ module MIDIMessage
46
46
  protected
47
47
 
48
48
  def self.included(base)
49
- base.include(ShortMessage)
50
- base.extend(ClassMethods)
49
+ base.send(:include, ShortMessage)
50
+ base.send(:extend, ClassMethods)
51
51
  end
52
52
 
53
53
  private
@@ -11,12 +11,12 @@ module MIDIMessage
11
11
  end
12
12
 
13
13
  def find(name)
14
- @constants.find { |const| const.key.to_s.downcase.eql?(name.to_s.downcase) }
14
+ @constants.find { |const| const.key.to_s.downcase == name.to_s.downcase }
15
15
  end
16
16
  alias_method :[], :find
17
17
 
18
18
  def find_by_value(value)
19
- @constants.find { |const| const.value.to_s.downcase.eql?(value.to_s.downcase) }
19
+ @constants.find { |const| const.value.to_s.downcase == value.to_s.downcase }
20
20
  end
21
21
 
22
22
  def self.all
@@ -26,7 +26,7 @@ module MIDIMessage
26
26
 
27
27
  def self.[](key)
28
28
  ensure_initialized
29
- @groups.find { |g| g.key.to_s.downcase.eql?(key.to_s.downcase) }
29
+ @groups.find { |g| g.key.to_s.downcase == key.to_s.downcase }
30
30
  end
31
31
 
32
32
  private
@@ -1,7 +1,3 @@
1
- #!/usr/bin/env ruby
2
- #
3
- #
4
-
5
1
  module MIDIMessage
6
2
 
7
3
  class Context
@@ -109,13 +109,13 @@ module MIDIMessage
109
109
 
110
110
  attr_reader :data
111
111
 
112
- def initialize(*a)
113
- options = a.last.kind_of?(Hash) ? a.pop : {}
112
+ def initialize(*args)
113
+ options = args.last.kind_of?(Hash) ? args.pop : {}
114
114
  @const = options[:const]
115
- id = @const.nil? ? a.shift : @const.value
115
+ id = @const.nil? ? args.shift : @const.value
116
116
  id = strip_redundant_nibble(id)
117
117
  initialize_short_message(0xF, id)
118
- @data = [a[0], a[1]]
118
+ @data = args.slice(0..1)
119
119
  end
120
120
 
121
121
  end
@@ -129,10 +129,10 @@ module MIDIMessage
129
129
 
130
130
  DISPLAY_NAME = "System Realtime"
131
131
 
132
- def initialize(*a)
133
- options = a.last.kind_of?(Hash) ? a.pop : {}
132
+ def initialize(*args)
133
+ options = args.last.kind_of?(Hash) ? args.pop : {}
134
134
  @const = options[:const]
135
- id = @const.nil? ? a[0] : @const.value
135
+ id = @const.nil? ? args.first : @const.value
136
136
  id = strip_redundant_nibble(id)
137
137
  initialize_short_message(0xF, id)
138
138
  end
@@ -149,7 +149,7 @@ module MIDIMessage
149
149
  # A command message is identified by having a status byte equal to 0x12
150
150
  class Command
151
151
 
152
- include SystemExclusive::InstanceMethods
152
+ include SystemExclusive
153
153
 
154
154
  attr_accessor :data
155
155
  alias_method :value, :data
@@ -158,7 +158,11 @@ module MIDIMessage
158
158
 
159
159
  def initialize(address, data, options = {})
160
160
  # store as a byte if it's a single byte
161
- @data = (data.kind_of?(Array) && data.length.eql?(1)) ? data[0] : data
161
+ @data = if data.kind_of?(Array) && data.length == 1
162
+ data.first
163
+ else
164
+ data
165
+ end
162
166
  initialize_sysex(address, options)
163
167
  end
164
168
 
@@ -168,7 +172,7 @@ module MIDIMessage
168
172
  # A request message is identified by having a status byte equal to 0x11
169
173
  class Request
170
174
 
171
- include SystemExclusive::InstanceMethods
175
+ include SystemExclusive
172
176
 
173
177
  attr_reader :size
174
178
  alias_method :value, :size
@@ -176,19 +180,23 @@ module MIDIMessage
176
180
  TypeByte = 0x11
177
181
 
178
182
  def initialize(address, size, options = {})
179
- self.size = (size.kind_of?(Array) && size.length.eql?(1)) ? size[0] : size
183
+ self.size = if size.kind_of?(Array) && size.count == 1
184
+ size.first
185
+ else
186
+ size
187
+ end
180
188
  initialize_sysex(address, options)
181
189
  end
182
190
 
183
- def size=(val)
191
+ def size=(value)
184
192
  # accepts a Numeric or Array but
185
193
  # must always store value as an array of three bytes
186
194
  size = []
187
- if val.kind_of?(Array) && val.size <= 3
188
- size = val
189
- elsif val.kind_of?(Numeric) && (((val + 1) / 247) <= 2)
195
+ if value.kind_of?(Array) && value.size <= 3
196
+ size = value
197
+ elsif value.kind_of?(Numeric) && (value + 1) / 247 <= 2
190
198
  size = []
191
- div, mod = *val.divmod(247)
199
+ div, mod = *value.divmod(247)
192
200
  size << mod unless mod.zero?
193
201
  div.times { size << 247 }
194
202
  end
@@ -4,7 +4,7 @@ module MIDIMessage
4
4
  module NoteMessage
5
5
 
6
6
  def self.included(base)
7
- base.include(ChannelMessage)
7
+ base.send(:include, ChannelMessage)
8
8
  end
9
9
 
10
10
  # The octave number of the note
@@ -1,48 +1,46 @@
1
- #!/usr/bin/env ruby
2
- #
3
-
4
1
  module MIDIMessage
5
2
 
6
- # very simple parsing
7
- # for more advanced parsing check out {nibbler}[http://github.com/arirusso/nibbler]
8
- class Parser
9
-
10
- # can take either a hex string eg Parser.new("904040")
11
- # or bytes eg Parser.new(0x90, 0x40, 0x40)
12
- # or an array of bytes eg Parser.new([0x90, 0x40, 0x40])
13
- def initialize(*a)
14
- @data = case a.first
15
- when Array then a.first
16
- when Numeric then a
17
- when String then TypeConversion.hex_string_to_numeric_byte_array(a.first)
18
- end
19
- end
20
-
21
- def parse
22
- first_nibble = ((@data.first & 0xF0) >> 4)
23
- second_nibble = (@data.first & 0x0F)
24
- case first_nibble
25
- when 0x8 then NoteOff.new(second_nibble, @data[1], @data[2])
26
- when 0x9 then NoteOn.new(second_nibble, @data[1], @data[2])
27
- when 0xA then PolyphonicAftertouch.new(second_nibble, @data[1], @data[2])
28
- when 0xB then ControlChange.new(second_nibble, @data[1], @data[2])
29
- when 0xC then ProgramChange.new(second_nibble, @data[1])
30
- when 0xD then ChannelAftertouch.new(second_nibble, @data[1])
31
- when 0xE then PitchBend.new(second_nibble, @data[1], @data[2])
32
- when 0xF then case second_nibble
33
- when 0x0 then SystemExclusive.new(*@data)
34
- when 0x1..0x6 then SystemCommon.new(second_nibble, @data[1], @data[2])
35
- when 0x8..0xF then SystemRealtime.new(second_nibble)
36
- else nil
37
- end
38
- else nil
3
+ # Very simple parsing
4
+ # for more advanced parsing check out {nibbler}[http://github.com/arirusso/nibbler]
5
+ class Parser
6
+
7
+ # Can take either a hex string eg Parser.new("904040")
8
+ # or bytes eg Parser.new(0x90, 0x40, 0x40)
9
+ # or an array of bytes eg Parser.new([0x90, 0x40, 0x40])
10
+ def initialize(*args)
11
+ @data = case args.first
12
+ when Array then args.first
13
+ when Numeric then args
14
+ when String then TypeConversion.hex_string_to_numeric_byte_array(args.first)
15
+ end
16
+ end
17
+
18
+ # Parse the data and return a message
19
+ def parse
20
+ first_nibble = ((@data.first & 0xF0) >> 4)
21
+ second_nibble = (@data.first & 0x0F)
22
+ case first_nibble
23
+ when 0x8 then NoteOff.new(second_nibble, @data[1], @data[2])
24
+ when 0x9 then NoteOn.new(second_nibble, @data[1], @data[2])
25
+ when 0xA then PolyphonicAftertouch.new(second_nibble, @data[1], @data[2])
26
+ when 0xB then ControlChange.new(second_nibble, @data[1], @data[2])
27
+ when 0xC then ProgramChange.new(second_nibble, @data[1])
28
+ when 0xD then ChannelAftertouch.new(second_nibble, @data[1])
29
+ when 0xE then PitchBend.new(second_nibble, @data[1], @data[2])
30
+ when 0xF then case second_nibble
31
+ when 0x0 then SystemExclusive.new(*@data)
32
+ when 0x1..0x6 then SystemCommon.new(second_nibble, @data[1], @data[2])
33
+ when 0x8..0xF then SystemRealtime.new(second_nibble)
34
+ else nil
39
35
  end
36
+ else nil
40
37
  end
41
-
42
- end
43
-
44
- def self.parse(*a)
45
- Parser.new(*a).parse
46
- end
38
+ end
39
+
40
+ end
41
+
42
+ def self.parse(*args)
43
+ Parser.new(*args).parse
44
+ end
47
45
 
48
46
  end
@@ -35,7 +35,7 @@ module MIDIMessage
35
35
  protected
36
36
 
37
37
  def self.included(base)
38
- base.extend(ClassMethods)
38
+ base.send(:extend, ClassMethods)
39
39
  end
40
40
 
41
41
  def update
@@ -3,6 +3,10 @@ module MIDIMessage
3
3
  # MIDI System-Exclusive Messages (SysEx)
4
4
  module SystemExclusive
5
5
 
6
+ def self.included(base)
7
+ base.send(:include, InstanceMethods)
8
+ end
9
+
6
10
  # Common SysEx data that a message class will contain
7
11
  module InstanceMethods
8
12
 
@@ -15,16 +19,17 @@ module MIDIMessage
15
19
  # an array of message parts. multiple byte parts will be represented as an array of bytes
16
20
  def to_a(options = {})
17
21
  omit = options[:omit] || []
22
+ node = @node.to_a(options) unless @node.nil? || omit.include?(:node)
18
23
  # this may need to be cached when properties are updated
19
24
  # might be worth benchmarking
20
25
  [
21
- self.class::StartByte,
22
- (@node.to_a(options) unless @node.nil? || omit.include?(:node)),
26
+ start_byte,
27
+ node,
23
28
  (type_byte unless omit.include?(:type)),
24
29
  [address].compact.flatten,
25
30
  [value].compact.flatten,
26
31
  (checksum unless omit.include?(:checksum)),
27
- self.class::EndByte
32
+ end_byte
28
33
  ].compact
29
34
  end
30
35
 
@@ -39,7 +44,12 @@ module MIDIMessage
39
44
 
40
45
  # string representation of the object's bytes
41
46
  def to_hex_s
42
- to_bytes.map { |b| s = b.to_s(16); s.length.eql?(1) ? "0#{s}" : s }.join.upcase
47
+ strings = to_bytes.map do |byte|
48
+ string = byte.to_s(16)
49
+ string = "0#{string}" if string.length == 1
50
+ string
51
+ end
52
+ strings.join.upcase
43
53
  end
44
54
  alias_method :to_bytestr, :to_hex_s
45
55
 
@@ -48,6 +58,14 @@ module MIDIMessage
48
58
  end
49
59
  alias_method :verbose_name, :name
50
60
 
61
+ def start_byte
62
+ self.class::StartByte
63
+ end
64
+
65
+ def end_byte
66
+ self.class::EndByte
67
+ end
68
+
51
69
  def type_byte
52
70
  self.class::TypeByte
53
71
  end
@@ -55,8 +73,9 @@ module MIDIMessage
55
73
  # alternate method from
56
74
  # http://www.2writers.com/eddie/TutSysEx.htm
57
75
  def checksum
58
- sum = (address + [value].flatten).inject { |a, b| a + b }
59
- (128 - sum.divmod(128)[1])
76
+ sum = (address + [value].flatten).inject(&:+)
77
+ mod = sum.divmod(128)[1]
78
+ 128 - mod
60
79
  end
61
80
 
62
81
  private
@@ -78,20 +97,25 @@ module MIDIMessage
78
97
  attr_accessor :data
79
98
 
80
99
  def initialize(data, options = {})
81
- @data = (data.kind_of?(Array) && data.length.eql?(1)) ? data[0] : data
100
+ @data = if data.kind_of?(Array) && data.length == 1
101
+ data.first
102
+ else
103
+ data
104
+ end
82
105
  initialize_sysex(nil, options)
83
106
  end
84
107
 
85
108
  # an array of message parts. multiple byte parts will be represented as an array of bytes
86
109
  def to_a(options = {})
87
110
  omit = options[:omit] || []
111
+ node = @node.to_a(options) unless @node.nil? || omit.include?(:node)
88
112
  # this may need to be cached when properties are updated
89
113
  # might be worth benchmarking
90
114
  [
91
- self.class::StartByte,
92
- (@node.to_a(options) unless @node.nil? || omit.include?(:node)),
115
+ start_byte,
116
+ node,
93
117
  @data,
94
- self.class::EndByte
118
+ end_byte
95
119
  ].compact
96
120
  end
97
121
 
@@ -109,16 +133,17 @@ module MIDIMessage
109
133
  def initialize(manufacturer, options = {})
110
134
  @device_id = options[:device_id]
111
135
  @model_id = options[:model_id]
112
- @manufacturer_id = manufacturer.kind_of?(Numeric) ? manufacturer : Constant.find("Manufacturer", manufacturer).value
136
+ @manufacturer_id = get_manufacturer_id(manufacturer)
113
137
  end
114
138
 
115
139
  def to_a(options = {})
116
- omit = options[:omit] || []
117
- [
118
- (@manufacturer_id unless omit.include?(:manufacturer) || omit.include?(:manufacturer_id)),
119
- (@device_id unless omit.include?(:device) || omit.include?(:device_id)),
120
- (@model_id unless omit.include?(:model) || omit.include?(:model_id))
121
- ].compact
140
+ omit = options[:omit] || []
141
+ properties = [:manufacturer, :device, :model].map do |property|
142
+ unless omit.include?(property) || omit.include?("#{property.to_s}_id")
143
+ instance_variable_get("@#{property.to_s}_id")
144
+ end
145
+ end
146
+ properties.compact
122
147
  end
123
148
 
124
149
  # this message takes a prototype message, copies it, and returns the copy with its node set
@@ -143,6 +168,17 @@ module MIDIMessage
143
168
  request
144
169
  end
145
170
 
171
+ private
172
+
173
+ def get_manufacturer_id(manufacturer)
174
+ if manufacturer.kind_of?(Numeric)
175
+ manufacturer
176
+ else
177
+ const = Constant.find("Manufacturer", manufacturer)
178
+ const.value
179
+ end
180
+ end
181
+
146
182
  end
147
183
 
148
184
  # Convert raw MIDI data to SysEx message objects
@@ -151,7 +187,7 @@ module MIDIMessage
151
187
  start_status = bytes.shift
152
188
  end_status = bytes.pop
153
189
 
154
- if start_status.eql?(0xF0) && end_status.eql?(0xF7)
190
+ if start_status == 0xF0 && end_status == 0xF7
155
191
 
156
192
  type_byte = bytes[3]
157
193
 
@@ -4,7 +4,7 @@ module MIDIMessage
4
4
  module SystemMessage
5
5
 
6
6
  def self.included(base)
7
- base.include(ShortMessage)
7
+ base.send(:include, ShortMessage)
8
8
  end
9
9
 
10
10
  # In the case of something like SystemCommon.new(0xF2, 0x00, 0x08), the first nibble F is redundant because
@@ -5,8 +5,13 @@ module MIDIMessage
5
5
 
6
6
  extend self
7
7
 
8
+ # Convert an array of hex nibbles to an array of numeric bytes
9
+ # eg ["9", "0", "4", "0"] to [0x90, 0x40]
10
+ #
11
+ # @param [Array<String>] An array of hex nibbles eg ["9", "0", "4", "0"]
12
+ # @return [Array<Fixnum] An array of numeric bytes eg [0x90, 0x40]
8
13
  def hex_chars_to_numeric_byte_array(nibbles)
9
- nibbles = nibbles.dup
14
+ nibbles = nibbles.dup # Don't mess with the input
10
15
  # get rid of last nibble if there's an odd number
11
16
  # it will be processed later anyway
12
17
  nibbles.slice!(nibbles.length-2, 1) if nibbles.length.odd?
@@ -18,30 +23,57 @@ module MIDIMessage
18
23
  bytes
19
24
  end
20
25
 
21
- # Convert byte str to byte array
22
- def hex_string_to_numeric_byte_array(str)
23
- str = str.dup
26
+ # Convert byte string to an array of numeric bytes
27
+ # eg. "904040" to [0x90, 0x40, 0x40]
28
+ # @param [String] string A string representing hex digits eg "904040"
29
+ # @return [Array<Fixnum>] An array of numeric bytes eg [0x90, 0x40, 0x40]
30
+ def hex_string_to_numeric_byte_array(string)
31
+ string = string.dup
24
32
  bytes = []
25
- until str.eql?("")
26
- bytes << str.slice!(0, 2).hex
33
+ until string.length == 0
34
+ bytes << string.slice!(0, 2).hex
27
35
  end
28
36
  bytes
29
37
  end
30
38
 
31
- # Converts a string of hex digits to bytes
32
- def hex_str_to_hex_chars(str)
33
- str.split(//)
39
+ # Convert a string of hex digits to an array of nibbles
40
+ # eg. "904040" to ["9", "0", "4", "0", "4", "0"]
41
+ # @param [String] string A string representing hex digits eg "904040"
42
+ # @return [Array<String>] An array of hex nibble chars eg ["9", "0", "4", "0", "4", "0"]
43
+ def hex_str_to_hex_chars(string)
44
+ string.split(//)
34
45
  end
35
46
 
47
+ # Convert an array of numeric bytes to a string of hex digits
48
+ # eg. [0x90, 0x40, 0x40] to "904040"
49
+ # @param [Array<Fixnum>] bytes An array of numeric bytes eg [0x90, 0x40, 0x40]
50
+ # @return [String] A string representing hex digits eg "904040"
36
51
  def numeric_byte_array_to_hex_string(bytes)
37
- bytes.map { |b| s = b.to_s(16); s.length.eql?(1) ? "0#{s}" : s }.join.upcase
52
+ string_bytes = bytes.map do |byte|
53
+ string = byte.to_s(16)
54
+ string = "0#{string}" if string.length == 1
55
+ string
56
+ end
57
+ string_bytes.join.upcase
38
58
  end
39
59
 
60
+ # Convert a numeric byte to hex chars
61
+ # eg 0x90 to ["9", "0"]
62
+ # @param [Fixnum] num A numeric byte eg 0x90
63
+ # @return [Array<String>] An array of hex nibble chars eg ["9", "0"]
40
64
  def numeric_byte_to_hex_chars(num)
41
- [((num & 0xF0) >> 4), (num & 0x0F)].map { |n| n.to_s(16) }
65
+ nibbles = numeric_byte_to_nibbles(num)
66
+ nibbles.map { |n| n.to_s(16) }
67
+ end
68
+
69
+ # Convert a numeric byte to nibbles
70
+ # eg 0x90 to [0x9, 0x0]
71
+ # @param [Fixnum] num A numeric byte eg 0x90
72
+ # @return [Array<Fixnum>] An array of nibbles eg [0x9, 0x0]
73
+ def numeric_byte_to_nibbles(num)
74
+ [((num & 0xF0) >> 4), (num & 0x0F)]
42
75
  end
43
76
 
44
-
45
77
  end
46
78
 
47
79
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: midi-message
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Russo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-01 00:00:00.000000000 Z
11
+ date: 2014-09-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Objects and classes for dealing with MIDI messages.
14
14
  email: