midi-message 0.0.1-i686-linux

Sign up to get free protection for your applications and to get access to all the features.
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
+