midi-message 0.0.1-i686-linux

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.
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2010-2011 Ari Russo
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.rdoc ADDED
@@ -0,0 +1,24 @@
1
+ = midi-messages
2
+
3
+ == Summary
4
+
5
+ MIDI Messages in Ruby
6
+
7
+ == Features
8
+
9
+ * Objectification of the MIDI spec
10
+ * YAML Dictionary of MIDI constants
11
+
12
+ == Install
13
+
14
+ * gem install midi-message (*not yet available)
15
+
16
+ == Author
17
+
18
+ * {Ari Russo}[http://github.com/arirusso] <ari.russo at gmail.com>
19
+
20
+ == License
21
+
22
+ Apache 2.0, See the file LICENSE
23
+
24
+ Copyright (c) 2011 Ari Russo
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ module MIDIMessage
4
+
5
+ # common behavior amongst Channel Message types
6
+ module ChannelMessageBehavior
7
+
8
+ attr_reader :data,
9
+ :name,
10
+ :status
11
+
12
+ def initialize_channel_message(status_nibble_1, status_nibble_2, data_byte_1, data_byte_2 = 0)
13
+ @status = [status_nibble_1, status_nibble_2]
14
+ @data = [data_byte_1]
15
+ @data[1] = data_byte_2 if self.class::second_data_byte?
16
+ initialize_shortcuts
17
+ initialize_simple_message(status_nibble_1, status_nibble_2)
18
+ end
19
+
20
+ def to_a
21
+ db2 = self.class::second_data_byte? ? @data[1] : nil
22
+ [@status[0] + @status[1], @data[0], db2].compact
23
+ end
24
+ alias_method :to_byte_array, :to_a
25
+ alias_method :to_bytes, :to_a
26
+
27
+ def to_hex_s
28
+ to_a.join
29
+ end
30
+ alias_method :hex, :to_hex_s
31
+
32
+ def initialize(*a)
33
+ initialize_channel_message(self.class::TypeId, *a)
34
+ end
35
+
36
+ def self.included(base)
37
+ base.extend(ClassMethods)
38
+ end
39
+
40
+ module ClassMethods
41
+
42
+ def type_for_status
43
+ 0 + (const_get(:TypeId) << 4)
44
+ end
45
+
46
+ def type_id(id)
47
+ const_set(:TypeId, id)
48
+ end
49
+
50
+ def schema(*args)
51
+ self.send(:const_set, :Shortcuts, args)
52
+ const_set(:NumDataBytes, args.length-1)
53
+ end
54
+ alias_method :layout, :schema
55
+
56
+ def second_data_byte?
57
+ num = const_get(:NumDataBytes)
58
+ !num.nil? && num > 1
59
+ end
60
+
61
+ end
62
+
63
+ def initialize_shortcuts
64
+ props = [
65
+ { :name => :status, :index => 1 },
66
+ { :name => :data, :index => 0 },
67
+ { :name => :data, :index => 1 }
68
+ ]
69
+ shortcuts = self.class.send(:const_get, :Shortcuts)
70
+ shortcuts.each_with_index do |prop,i|
71
+ self.class.send(:attr_reader, prop)
72
+ self.class.send(:define_method, "#{prop}=") do |val|
73
+ send(:instance_variable_set, "@#{prop.to_s}", val)
74
+ send(props[i][:name])[props[i][:index]] = val
75
+ end
76
+ instance_variable_set("@#{prop}", send(props[i][:name])[props[i][:index]])
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ # use this if you want to instantiate a raw channel message
84
+ #
85
+ # example = ChannelMessage.new(0x9, 0x0, 0x40, 0x57) # creates a raw note-on message
86
+ #
87
+ class ChannelMessage
88
+
89
+ include SimpleMessageBehavior
90
+ include ChannelMessageBehavior
91
+
92
+ display_name 'Channel Message'
93
+
94
+ def initialize(*a)
95
+ initialize_channel_message(*a)
96
+ end
97
+
98
+ end
99
+
100
+ #
101
+ # MIDI Channel Aftertouch message
102
+ #
103
+ class ChannelAftertouch
104
+
105
+ include SimpleMessageBehavior
106
+ include ChannelMessageBehavior
107
+
108
+ schema :channel, :value
109
+ type_id 0xD
110
+ display_name 'Channel Aftertouch'
111
+
112
+ end
113
+
114
+ #
115
+ # MIDI Control Change message
116
+ #
117
+ class ControlChange
118
+
119
+ include SimpleMessageBehavior
120
+ include ChannelMessageBehavior
121
+
122
+ schema :channel, :number, :value
123
+ type_id 0xB
124
+ display_name 'Control Change'
125
+ identifier :number
126
+
127
+ end
128
+
129
+ #
130
+ # MIDI Note-Off message
131
+ #
132
+ class NoteOff
133
+
134
+ include SimpleMessageBehavior
135
+ include ChannelMessageBehavior
136
+
137
+ schema :channel, :note, :velocity
138
+ type_id 0x8
139
+ display_name 'Note Off'
140
+ use_constants 'Note'
141
+ identifier :note
142
+
143
+ end
144
+
145
+ #
146
+ # MIDI Note-On message
147
+ #
148
+ class NoteOn
149
+
150
+ include SimpleMessageBehavior
151
+ include ChannelMessageBehavior
152
+
153
+ schema :channel, :note, :velocity
154
+ type_id 0x9
155
+ display_name 'Note On'
156
+ use_constants 'Note'
157
+ identifier :note
158
+
159
+ end
160
+
161
+ #
162
+ # MIDI Pitch Bend message
163
+ #
164
+ class PitchBend
165
+
166
+ include SimpleMessageBehavior
167
+ include ChannelMessageBehavior
168
+
169
+ schema :channel, :low, :high
170
+ type_id 0xE
171
+ DisplayName = 'Pitch Bend'
172
+
173
+ end
174
+
175
+ #
176
+ # MIDI Polyphonic (note specific) Aftertouch message
177
+ #
178
+ class PolyphonicAftertouch
179
+
180
+ include SimpleMessageBehavior
181
+ include ChannelMessageBehavior
182
+
183
+ schema :channel, :note, :value
184
+ type_id 0xA
185
+ DisplayName = 'Polyphonic Aftertouch'
186
+
187
+ end
188
+
189
+ #
190
+ # MIDI Program Change message
191
+ #
192
+ class ProgramChange
193
+
194
+ include SimpleMessageBehavior
195
+ include ChannelMessageBehavior
196
+
197
+ schema :channel, :program
198
+ type_id 0xC
199
+ DisplayName = 'Program Change'
200
+
201
+ end
202
+
203
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ require 'yaml'
4
+ require 'singleton'
5
+
6
+ module MIDIMessage
7
+
8
+ # MIDI Constants
9
+ class Constant
10
+
11
+ include Singleton
12
+
13
+ def initialize
14
+ # cache the constants data
15
+ require 'midi-message/constants'
16
+ @dict = YAML::load(@@data)
17
+ end
18
+
19
+ def [](key)
20
+ @dict[key]
21
+ end
22
+
23
+ def self.[](key)
24
+ instance[key]
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,103 @@
1
+ # better way to do this?
2
+ @@data = %q{
3
+
4
+ Control Change:
5
+ Bank Select: 0
6
+ Modulation Wheel: 1
7
+ Breath Controller: 2
8
+ Foot Controller: 4
9
+ Portamento Time: 5
10
+ Data Entry MSB: 6
11
+ Channel Volume: 7
12
+ Balance: 8
13
+ Pan: 10
14
+ Expression Controller: 11
15
+ General Purpose Controllers: 16
16
+ General Purpose Controllers: 17
17
+ General Purpose Controllers: 18
18
+ General Purpose Controllers: 19
19
+ LSB for controller 0: 32
20
+ LSB for controller 1: 33
21
+ LSB for controller 2: 34
22
+ LSB for controller 3: 35
23
+ LSB for controller 4: 36
24
+ LSB for controller 5: 37
25
+ LSB for controller 6: 38
26
+ LSB for controller 7: 39
27
+ LSB for controller 8: 40
28
+ LSB for controller 9: 41
29
+ LSB for controller 10: 42
30
+ LSB for controller 11: 43
31
+ LSB for controller 12: 44
32
+ LSB for controller 13: 45
33
+ LSB for controller 14: 46
34
+ LSB for controller 15: 47
35
+ LSB for controller 16: 48
36
+ LSB for controller 17: 49
37
+ LSB for controller 18: 50
38
+ LSB for controller 19: 51
39
+ LSB for controller 20: 52
40
+ LSB for controller 21: 53
41
+ LSB for controller 22: 54
42
+ LSB for controller 23: 55
43
+ LSB for controller 24: 56
44
+ LSB for controller 25: 57
45
+ LSB for controller 26: 58
46
+ LSB for controller 27: 59
47
+ LSB for controller 28: 60
48
+ LSB for controller 29: 61
49
+ LSB for controller 30: 62
50
+ LSB for controller 31: 63
51
+ Hold Pedal: 64
52
+ Portamento: 65
53
+
54
+ Control Mode:
55
+ All Sound Off: 120
56
+ All Controllers Off: 121
57
+ Local Keyboard Toggle: 122
58
+ All Notes Off: 123
59
+ Omni Mode Off: 124
60
+ Omni Mode On: 125
61
+ Mono: 126
62
+ Poly: 127
63
+
64
+ System Realtime:
65
+ Start: 0xFA
66
+ Clock: 0xF8
67
+ Continue: 0xFB
68
+ Stop: 0xFC
69
+ Reset: 0xFF
70
+ ActiveSense: 0xFE
71
+
72
+ Manufacturers:
73
+
74
+ SequentialCircuits: 1
75
+ BigBriar: 2
76
+ Octave: 3
77
+ Moog: 4
78
+ Passport: 5
79
+ Lexicon: 6
80
+
81
+ PAIA: 0x11
82
+ Simmons: 0x12
83
+ GentleElectric: 0x13
84
+ Fairlight: 0x14
85
+ BonTempi: 0x20
86
+ SIEL: 0x21
87
+ SyntheAxe: 0x23
88
+
89
+ Kawai: 0x40
90
+ Roland: 0x41
91
+ Korg: 0x42
92
+ Yamaha: 0x43
93
+ Casio: 0x44
94
+ Akai: 0x47
95
+
96
+ Emagic: [0x00, 0x20, 0x31]
97
+ Behringer: [0x00, 0x20, 0x32]
98
+
99
+ Note:
100
+
101
+ C3: 64
102
+
103
+ }
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ module MIDIMessage
4
+
5
+ # very simple parsing
6
+ # for more advanced parsing check out {nibbler}[http://github.com/arirusso/nibbler]
7
+ class Parser
8
+
9
+ # can take either a hex string eg Parser.new("904040")
10
+ # or bytes eg Parser.new(0x90, 0x40, 0x40)
11
+ # or an array of bytes eg Parser.new([0x90, 0x40, 0x40])
12
+ def initialize(*a)
13
+ @data = case a.first
14
+ when Array then a.first
15
+ when Numeric then a
16
+ when String then str_to_bytes(a.first)
17
+ end
18
+ end
19
+
20
+ def parse
21
+ first_nibble = @data.first >> 4
22
+ second_nibble = @data.first >> 8
23
+ case first_nibble
24
+ when 0x8 then NoteOff.new(second_nibble, @data[1], @data[2])
25
+ when 0x9 then NoteOn.new(second_nibble, @data[1], @data[2])
26
+ when 0xA then PolyphonicAftertouch.new(second_nibble, @data[1], @data[2])
27
+ when 0xB then ControlChange.new(second_nibble, @data[1], @data[2])
28
+ when 0xC then ProgramChange.new(second_nibble, @data[1])
29
+ when 0xD then ChannelAftertouch.new(second_nibble, @data[1])
30
+ when 0xE then PitchBend.new(second_nibble, @data[1], @data[2])
31
+ when 0xF then case second_nibble
32
+ when 0x0 then SystemExclusive.new(*@data)
33
+ when 0x1..0x6 then SystemCommon.new(second_nibble, @data[1], @data[2])
34
+ when 0x8..0xF then SystemRealtime.new(second_nibble)
35
+ else nil
36
+ end
37
+ else nil
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ def self.parse(*a)
44
+ Parser.new(*a).parse
45
+ end
46
+
47
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ module MIDIMessage
4
+
5
+ # common behavior amongst all Message types
6
+ module SimpleMessageBehavior
7
+
8
+ attr_reader :name,
9
+ :status,
10
+ :verbose_name
11
+
12
+ def initialize_simple_message(status_nibble_1, status_nibble_2)
13
+ @status = [status_nibble_1, status_nibble_2]
14
+ group_name = self.class.const_get(:DisplayName)
15
+ group_name_alias = self.class.const_get(:UseConstants) rescue nil
16
+ val = self.send(self.class.const_get(:Identifier)) rescue @status[1]
17
+ group = Constant[group_name] || (group_name_alias.nil? ? nil : Constant[group_name_alias])
18
+ unless group.nil?
19
+ const = group.find { |k,v| k if v.eql?(val) }
20
+ unless const.nil?
21
+ @name = const.first
22
+ @verbose_name = "#{self.class::DisplayName}: #{const.first}"
23
+ end
24
+ end
25
+ end
26
+
27
+ def to_hex_s
28
+ to_a.join
29
+ end
30
+ alias_method :hex, :to_hex_s
31
+
32
+ def self.included(base)
33
+ base.extend(ClassMethods)
34
+ end
35
+
36
+ module ClassMethods
37
+
38
+ def display_name(name)
39
+ const_set(:DisplayName, name)
40
+ end
41
+
42
+ def use_constants(name)
43
+ const_set(:UseConstants, name)
44
+ end
45
+
46
+ def identifier(name)
47
+ const_set(:Identifier, name)
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #
4
+ module MIDIMessage
5
+
6
+ module SystemExclusive
7
+
8
+ # convert raw MIDI data to SysEx message objects
9
+ def self.new(*bytes)
10
+
11
+ start_status = bytes.shift
12
+ end_status = bytes.pop
13
+
14
+ return nil unless start_status.eql?(0xF0) && end_status.eql?(0xF7)
15
+
16
+ fixed_length_message_part = bytes.slice!(0,7)
17
+
18
+ manufacturer_id = fixed_length_message_part[0]
19
+ device_id = fixed_length_message_part[1]
20
+ model_id = fixed_length_message_part[2]
21
+
22
+ msg_class = case fixed_length_message_part[3]
23
+ when 0x11 then Request
24
+ when 0x12 then Command
25
+ end
26
+
27
+ address = fixed_length_message_part.slice(4,3)
28
+ checksum = bytes.slice!((bytes.length - 1), 1)
29
+ value = bytes
30
+
31
+ node = Node.new(manufacturer_id, model_id, :device_id => device_id)
32
+ msg_class.new(address, value, :checksum => checksum, :node => node)
33
+ end
34
+
35
+ # basic SysEx data that a message class will contain
36
+ module Data
37
+
38
+ attr_reader :address,
39
+ :checksum,
40
+ :device
41
+
42
+ StartByte = 0xF0
43
+ EndByte = 0xF7
44
+
45
+ # an array of message parts. multiple byte parts will be represented as an array of bytes
46
+ def to_a
47
+ array
48
+ end
49
+
50
+ # a flat array of message bytes
51
+ def to_byte_array
52
+ array.flatten
53
+ end
54
+
55
+ private
56
+
57
+ def address_to_i
58
+ address.inject { |a,b| a + b }
59
+ end
60
+
61
+ def value_to_i
62
+ value.kind_of?(Array) ? value.inject { |a,b| a + b } : value
63
+ end
64
+
65
+ def initialize_sysex(address, options = {})
66
+ @node = options[:node]
67
+ @checksum = options[:checksum]
68
+ @address = address
69
+ end
70
+
71
+ def array
72
+ # this may need to be cached when properties are updated
73
+ # might be worth benchmarking
74
+ @checksum = (128 - (address_to_i + value_to_i).divmod(128)[1])
75
+ [
76
+ StartByte,
77
+ @node.manufacturer,
78
+ (@device_id || @node.device_id),
79
+ @node.model_id,
80
+ status_byte,
81
+ address,
82
+ value,
83
+ @checksum,
84
+ EndByte
85
+ ]
86
+ end
87
+
88
+ end
89
+
90
+ # A SysEx command message
91
+ #
92
+ class Command
93
+
94
+ include Data
95
+
96
+ attr_reader :data
97
+
98
+ StatusByte = 0x12
99
+
100
+ def initialize(address, data, options = {})
101
+ @data = data
102
+ initialize_sysex(address, options)
103
+ end
104
+
105
+ def value
106
+ @data
107
+ end
108
+
109
+ def data=(val)
110
+ @data = val
111
+ update_byte_array
112
+ end
113
+
114
+ end
115
+
116
+ #
117
+ # The SystemExclusive::Node represents a hardware synthesizer or other MIDI device that a message
118
+ # is being sent to or received from.
119
+ #
120
+ class Node
121
+
122
+ attr_accessor :device_id # (Not to be confused with any kind of Device class in this library)
123
+ attr_reader :manufacturer, :model_id
124
+
125
+ def initialize(manufacturer, model_id, options = {})
126
+ @device_id = options[:device_id]
127
+ @model_id = model_id
128
+ @manufacturer = manufacturer
129
+ end
130
+
131
+ def message(*a)
132
+ a << { :node => self }
133
+ Command.new(*a)
134
+ end
135
+
136
+ end
137
+
138
+ # A SysEx request message
139
+ #
140
+ class Request
141
+
142
+ include Data
143
+
144
+ attr_accessor :size
145
+ alias_method :value, :size
146
+
147
+ StatusByte = 0x11
148
+
149
+ def initialize(address, size, options = {})
150
+ @size = size
151
+ initialize_sysex(address, options = {})
152
+ end
153
+
154
+ end
155
+
156
+ end
157
+
158
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ module MIDIMessage
4
+
5
+ #
6
+ # MIDI System-Common message
7
+ #
8
+ class SystemCommon
9
+
10
+ include SimpleMessageBehavior
11
+ display_name 'System Common'
12
+
13
+ attr_reader :status,
14
+ :data
15
+
16
+ def initialize(status_nibble_2, data_byte_1 = nil, data_byte_2 = nil)
17
+ @data = [data_byte_1, data_byte_2]
18
+ initialize_simple_message(0xF, status_nibble_2)
19
+ end
20
+
21
+ end
22
+
23
+ #
24
+ # MIDI System-Realtime message
25
+ #
26
+ class SystemRealtime
27
+
28
+ include SimpleMessageBehavior
29
+ display_name 'System Realtime'
30
+
31
+ attr_reader :status
32
+
33
+ def initialize(id)
34
+ initialize_simple_message(0xF, id)
35
+ end
36
+
37
+ def id
38
+ @status[1]
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # MIDI Messages in Ruby
4
+ #
5
+ module MIDIMessage
6
+
7
+ VERSION = "0.0.1"
8
+
9
+ end
10
+
11
+ require 'midi-message/simple_message'
12
+ require 'midi-message/channel_message'
13
+ require 'midi-message/constant'
14
+ require 'midi-message/parser'
15
+ require 'midi-message/system_message'
16
+ require 'midi-message/system_exclusive'
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: midi-message
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: i686-linux
7
+ authors:
8
+ - Ari Russo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-29 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: MIDI Messages, objectified in Ruby.
18
+ email:
19
+ - ari.russo@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - lib/midi-message.rb
28
+ - lib/midi-message/system_exclusive.rb
29
+ - lib/midi-message/channel_message.rb
30
+ - lib/midi-message/simple_message.rb
31
+ - lib/midi-message/constants.rb
32
+ - lib/midi-message/parser.rb
33
+ - lib/midi-message/system_message.rb
34
+ - lib/midi-message/constant.rb
35
+ - LICENSE
36
+ - README.rdoc
37
+ has_rdoc: true
38
+ homepage: http://github.com/arirusso/midi-message
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.6
58
+ requirements: []
59
+
60
+ rubyforge_project: midi-message
61
+ rubygems_version: 1.6.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: MIDI Messages in Ruby.
65
+ test_files: []
66
+