midi-message 0.3.2 → 0.4.1
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 +7 -0
- data/LICENSE +2 -2
- data/README.md +120 -0
- data/lib/midi-message/channel_message.rb +67 -124
- data/lib/midi-message/constant.rb +0 -3
- data/lib/midi-message/message.rb +204 -0
- data/lib/midi-message/note_message.rb +16 -46
- data/lib/midi-message/short_message.rb +45 -29
- data/lib/midi-message/system_exclusive.rb +43 -103
- data/lib/midi-message/system_message.rb +7 -53
- data/lib/midi-message/type_conversion.rb +11 -11
- data/lib/midi-message.rb +13 -24
- data/test/{test_constants.rb → constants_test.rb} +0 -0
- data/test/{test_context.rb → context_test.rb} +0 -0
- data/test/{test_mutability.rb → mutability_test.rb} +0 -0
- data/test/{test_parser.rb → parser_test.rb} +0 -0
- data/test/{test_short_message.rb → short_message_test.rb} +0 -0
- data/test/{test_system_exclusive.rb → system_exclusive_test.rb} +0 -0
- data/test/{test_system_message.rb → system_message_test.rb} +0 -0
- metadata +22 -33
- data/README.rdoc +0 -100
- data/TODO +0 -0
- data/lib/midi-message/event/note.rb +0 -31
- data/lib/midi-message/process/filter.rb +0 -63
- data/lib/midi-message/process/limit.rb +0 -36
- data/lib/midi-message/process/processor.rb +0 -39
- data/lib/midi-message/process/transpose.rb +0 -30
- data/test/test_filter.rb +0 -115
- data/test/test_limit.rb +0 -46
- data/test/test_note_event.rb +0 -32
- data/test/test_processor.rb +0 -19
- data/test/test_transpose.rb +0 -39
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ad978e231aef5931892a5fb96573c4e709f3ad64
|
4
|
+
data.tar.gz: 53cc976f50cb5c4d5ba619f3d3d4b1aaa10a71d9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a51573df46bbee8bc764be4d139b52c7366c192c0402846bb3cae67efa4e5cbfa87b4ad1982765fc80f2d6d3e088c857f6ee5a9b0bc6d0f68a2e2ca08f3a931
|
7
|
+
data.tar.gz: c7264a018b5b523aeaa7391ab2f387aab0a2a9b66f583692bdd05a12eb7968c9ebc0ef120de61cfe82ab42e6f8c3301522fe957f6fc9ca9b5969d387ff8f1c5c
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright
|
1
|
+
Copyright 2011-2014 Ari Russo
|
2
2
|
|
3
3
|
Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
you may not use this file except in compliance with the License.
|
@@ -10,4 +10,4 @@ Unless required by applicable law or agreed to in writing, software
|
|
10
10
|
distributed under the License is distributed on an "AS IS" BASIS,
|
11
11
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
See the License for the specific language governing permissions and
|
13
|
-
limitations under the License.
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# MIDI Message
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Ruby MIDI message objects
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Flexible API to accommodate various sources and destinations of MIDI data
|
10
|
+
* Simple approach to System Exclusive data and devices
|
11
|
+
* [YAML dictionary of MIDI constants](https://github.com/arirusso/midi-message/blob/master/lib/midi.yml)
|
12
|
+
|
13
|
+
## Install
|
14
|
+
|
15
|
+
`gem install midi-message`
|
16
|
+
|
17
|
+
Or if you're using Bundler, add this to your Gemfile
|
18
|
+
|
19
|
+
`gem "midi-message"`
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require "midi-message"
|
25
|
+
|
26
|
+
include MIDIMessage
|
27
|
+
```
|
28
|
+
|
29
|
+
#### Basic Messages
|
30
|
+
|
31
|
+
There are a few ways to create a new MIDI message. Here are some examples
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
NoteOn.new(0, 64, 64)
|
35
|
+
|
36
|
+
NoteOn["E4"].new(0, 100)
|
37
|
+
|
38
|
+
with(:channel => 0, :velocity => 100) { note_on("E4") }
|
39
|
+
```
|
40
|
+
|
41
|
+
Those expressions all evaluate to the same object
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
#<MIDIMessage::NoteOn:0x9c1c240
|
45
|
+
@channel=0,
|
46
|
+
@data=[64, 64],
|
47
|
+
@name="E4",
|
48
|
+
@note=64,
|
49
|
+
@status=[9, 0],
|
50
|
+
@velocity=64,
|
51
|
+
@verbose_name="Note On: E4">
|
52
|
+
```
|
53
|
+
|
54
|
+
#### SysEx Messages
|
55
|
+
|
56
|
+
As with any kind of message, you can begin with raw data
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
SystemExclusive.new(0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7)
|
60
|
+
```
|
61
|
+
|
62
|
+
Or in a more object oriented way
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
synth = SystemExclusive::Node.new(0x41, :model_id => 0x42, :device_id => 0x10)
|
66
|
+
|
67
|
+
SystemExclusive::Command.new([0x40, 0x7F, 0x00], 0x00, :node => synth)
|
68
|
+
```
|
69
|
+
|
70
|
+
A Node represents a device that you're sending a message to (eg. your Yamaha DX7 is a Node). Sysex messages can either be a Command or Request
|
71
|
+
|
72
|
+
You can use the Node to instantiate a message
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
synth.command([0x40, 0x7F, 0x00], 0x00)
|
76
|
+
```
|
77
|
+
|
78
|
+
One way or another, you will wind up with a pair of objects like this
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
#<MIDIMessage::SystemExclusive::Command:0x9c1e57c
|
82
|
+
@address=[64, 0, 127],
|
83
|
+
@checksum=[65],
|
84
|
+
@data=[0],
|
85
|
+
@node=
|
86
|
+
#<MIDIMessage::SystemExclusive::Node:0x9c1e5a4
|
87
|
+
@device_id=16,
|
88
|
+
@manufacturer_id=65,
|
89
|
+
@model_id=66>>
|
90
|
+
```
|
91
|
+
|
92
|
+
#### Parsing
|
93
|
+
|
94
|
+
The parse method will take any valid message data and return the object representation
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
MIDIMessage.parse(0x90, 0x40, 0x40)
|
98
|
+
|
99
|
+
#<MIDIMessage::NoteOn:0x9c1c240 ..>
|
100
|
+
|
101
|
+
MIDIMessage.parse(0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7)
|
102
|
+
|
103
|
+
#<MIDIMessage::SystemExclusive::Command:0x9c1e57c ..>
|
104
|
+
```
|
105
|
+
|
106
|
+
Check out [nibbler](http://github.com/arirusso/nibbler) for more advanced parsing
|
107
|
+
|
108
|
+
## Documentation
|
109
|
+
|
110
|
+
* [rdoc](http://rubydoc.info/github/arirusso/midi-message)
|
111
|
+
|
112
|
+
## Author
|
113
|
+
|
114
|
+
* [Ari Russo](http://github.com/arirusso) <ari.russo at gmail.com>
|
115
|
+
|
116
|
+
## License
|
117
|
+
|
118
|
+
Apache 2.0, See the file LICENSE
|
119
|
+
|
120
|
+
Copyright (c) 2011-2014 Ari Russo
|
@@ -1,29 +1,27 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
1
|
module MIDIMessage
|
4
2
|
|
5
|
-
#
|
3
|
+
# Common behavior amongst Channel Message types
|
6
4
|
module ChannelMessage
|
7
5
|
|
8
|
-
attr_reader :data,
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
attr_reader :data, :name
|
7
|
+
|
8
|
+
# Shortcut to RawChannelMessage.new
|
9
|
+
# aka build a ChannelMessage from raw nibbles and bytes
|
10
|
+
# eg ChannelMessage.new(0x9, 0x0, 0x40, 0x40)
|
11
|
+
# @param [*Array<Fixnum>] data The status nibbles and data bytes
|
12
|
+
# @return [RawChannelMessage] The resulting RawChannelMessage object
|
13
|
+
def self.new(*data, &block)
|
14
|
+
Message.new(*data, &block)
|
13
15
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
ind ||= 0
|
22
|
-
a.insert(ind, @const.value)
|
23
|
-
end
|
24
|
-
initialize_channel_message(self.class.type_for_status, *a)
|
16
|
+
|
17
|
+
# @param [*Array<Fixnum>] data The status nibbles and data bytes
|
18
|
+
def initialize(*data)
|
19
|
+
data = data.dup
|
20
|
+
options = data.last.kind_of?(Hash) ? data.pop : {}
|
21
|
+
processed_data = options[:const].nil? ? data : data_with_const(data, options[:const])
|
22
|
+
initialize_channel_message(self.class.type_for_status, *processed_data)
|
25
23
|
end
|
26
|
-
|
24
|
+
|
27
25
|
def initialize_properties
|
28
26
|
props = [
|
29
27
|
{ :name => :status, :index => 1 },
|
@@ -44,15 +42,22 @@ module MIDIMessage
|
|
44
42
|
end
|
45
43
|
end
|
46
44
|
end
|
47
|
-
|
45
|
+
|
48
46
|
protected
|
49
|
-
|
47
|
+
|
50
48
|
def self.included(base)
|
49
|
+
base.include(ShortMessage)
|
51
50
|
base.extend(ClassMethods)
|
52
51
|
end
|
53
52
|
|
54
53
|
private
|
55
|
-
|
54
|
+
|
55
|
+
def data_with_const(data, const)
|
56
|
+
key = self.class.constant_property
|
57
|
+
ind = self.class.properties.index(key) || 0
|
58
|
+
data.insert(ind, const.value)
|
59
|
+
end
|
60
|
+
|
56
61
|
def initialize_channel_message(status_nibble_1, status_nibble_2, data_byte_1, data_byte_2 = 0)
|
57
62
|
@status = [status_nibble_1, status_nibble_2]
|
58
63
|
@data = [data_byte_1]
|
@@ -60,120 +65,58 @@ module MIDIMessage
|
|
60
65
|
initialize_properties
|
61
66
|
initialize_short_message(status_nibble_1, status_nibble_2)
|
62
67
|
end
|
63
|
-
|
68
|
+
|
69
|
+
# For defining Channel Message class types
|
64
70
|
module ClassMethods
|
65
|
-
|
66
|
-
|
67
|
-
|
71
|
+
|
72
|
+
# Get the status nibble for this particular message type
|
73
|
+
# @return [Fixnum] The status nibble
|
68
74
|
def type_for_status
|
69
|
-
|
75
|
+
Status[display_name]
|
70
76
|
end
|
71
77
|
|
72
|
-
def
|
73
|
-
|
78
|
+
def properties
|
79
|
+
const_get("DATA") if const_defined?("DATA")
|
74
80
|
end
|
75
|
-
alias_method :layout, :schema
|
76
81
|
|
82
|
+
# Does the schema of this Channel Message carry a second data byte?
|
83
|
+
# eg. NoteMessage does, and ProgramChange doesn"t
|
84
|
+
# @return [Boolean] Is there a second data byte on this message type?
|
77
85
|
def second_data_byte?
|
78
|
-
|
86
|
+
properties.nil? || (properties.length-1) > 1
|
79
87
|
end
|
80
88
|
|
81
89
|
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
# use this if you want to instantiate a raw channel message
|
86
|
-
#
|
87
|
-
# example = ChannelMessage.new(0x9, 0x0, 0x40, 0x57) # creates a raw note-on message
|
88
|
-
#
|
89
|
-
class RawChannelMessage
|
90
|
-
|
91
|
-
include ShortMessage
|
92
|
-
include ChannelMessage
|
93
|
-
|
94
|
-
use_display_name 'Channel Message'
|
95
|
-
|
96
|
-
def initialize(*a)
|
97
|
-
initialize_channel_message(*a)
|
98
|
-
end
|
99
|
-
|
100
|
-
def to_type
|
101
|
-
status = (@status[0] << 4) + (@status[1])
|
102
|
-
MIDIMessage.parse(status, *@data)
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
#
|
108
|
-
# MIDI Channel Aftertouch message
|
109
|
-
#
|
110
|
-
class ChannelAftertouch
|
111
|
-
|
112
|
-
include ShortMessage
|
113
|
-
include ChannelMessage
|
114
90
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
include ShortMessage
|
142
|
-
include ChannelMessage
|
143
|
-
|
144
|
-
schema :channel, :low, :high
|
145
|
-
use_display_name 'Pitch Bend'
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
#
|
150
|
-
# MIDI Polyphonic (note specific) Aftertouch message
|
151
|
-
#
|
152
|
-
class PolyphonicAftertouch
|
153
|
-
|
154
|
-
include ShortMessage
|
155
|
-
include ChannelMessage
|
91
|
+
# Use this if you want to instantiate a raw channel message
|
92
|
+
#
|
93
|
+
# For example ChannelMessage::Message.new(0x9, 0x0, 0x40, 0x57)
|
94
|
+
# creates a raw note-on message
|
95
|
+
class Message
|
96
|
+
|
97
|
+
include ChannelMessage
|
98
|
+
|
99
|
+
DISPLAY_NAME = "Channel Message"
|
100
|
+
|
101
|
+
# Build a Channel Mssage from raw nibbles and bytes
|
102
|
+
# eg ChannelMessage.new(0x9, 0x0, 0x40, 0x40)
|
103
|
+
# @param [*Array<Fixnum>] data The status nibbles and data bytes
|
104
|
+
# @return [RawChannelMessage] The resulting RawChannelMessage object
|
105
|
+
def initialize(*data)
|
106
|
+
initialize_channel_message(*data)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Convert this RawChannelMessage to one of the more specific ChannelMessage types
|
110
|
+
# eg. RawChannelMessage.new(0x9, 0x0, 0x40, 0x40).to_type would result in
|
111
|
+
# NoteMessage.new(0x0, 0x40, 0x40)
|
112
|
+
# @return [ChannelMessage] The resulting specific ChannelMessage object
|
113
|
+
def to_type
|
114
|
+
status = (@status[0] << 4) + (@status[1])
|
115
|
+
MIDIMessage.parse(status, *@data)
|
116
|
+
end
|
156
117
|
|
157
|
-
|
158
|
-
use_display_name 'Polyphonic Aftertouch'
|
159
|
-
use_constants 'Note', :for => :note
|
118
|
+
end
|
160
119
|
|
161
120
|
end
|
162
|
-
PolyAftertouch = PolyphonicAftertouch
|
163
|
-
PolyPressure = PolyphonicAftertouch
|
164
|
-
PolyphonicPressure = PolyphonicAftertouch
|
165
121
|
|
166
|
-
#
|
167
|
-
# MIDI Program Change message
|
168
|
-
#
|
169
|
-
class ProgramChange
|
170
|
-
|
171
|
-
include ShortMessage
|
172
|
-
include ChannelMessage
|
173
|
-
|
174
|
-
schema :channel, :program
|
175
|
-
use_display_name 'Program Change'
|
176
|
-
|
177
|
-
end
|
178
|
-
|
179
122
|
end
|
@@ -0,0 +1,204 @@
|
|
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(*a)
|
113
|
+
options = a.last.kind_of?(Hash) ? a.pop : {}
|
114
|
+
@const = options[:const]
|
115
|
+
id = @const.nil? ? a.shift : @const.value
|
116
|
+
id = strip_redundant_nibble(id)
|
117
|
+
initialize_short_message(0xF, id)
|
118
|
+
@data = [a[0], a[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(*a)
|
133
|
+
options = a.last.kind_of?(Hash) ? a.pop : {}
|
134
|
+
@const = options[:const]
|
135
|
+
id = @const.nil? ? a[0] : @const.value
|
136
|
+
id = strip_redundant_nibble(id)
|
137
|
+
initialize_short_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::InstanceMethods
|
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 = (data.kind_of?(Array) && data.length.eql?(1)) ? data[0] : data
|
162
|
+
initialize_sysex(address, options)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
# A SysEx request message
|
168
|
+
# A request message is identified by having a status byte equal to 0x11
|
169
|
+
class Request
|
170
|
+
|
171
|
+
include SystemExclusive::InstanceMethods
|
172
|
+
|
173
|
+
attr_reader :size
|
174
|
+
alias_method :value, :size
|
175
|
+
|
176
|
+
TypeByte = 0x11
|
177
|
+
|
178
|
+
def initialize(address, size, options = {})
|
179
|
+
self.size = (size.kind_of?(Array) && size.length.eql?(1)) ? size[0] : size
|
180
|
+
initialize_sysex(address, options)
|
181
|
+
end
|
182
|
+
|
183
|
+
def size=(val)
|
184
|
+
# accepts a Numeric or Array but
|
185
|
+
# must always store value as an array of three bytes
|
186
|
+
size = []
|
187
|
+
if val.kind_of?(Array) && val.size <= 3
|
188
|
+
size = val
|
189
|
+
elsif val.kind_of?(Numeric) && (((val + 1) / 247) <= 2)
|
190
|
+
size = []
|
191
|
+
div, mod = *val.divmod(247)
|
192
|
+
size << mod unless mod.zero?
|
193
|
+
div.times { size << 247 }
|
194
|
+
end
|
195
|
+
(3 - size.size).times { size.unshift 0 }
|
196
|
+
@size = size
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
@@ -1,70 +1,40 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
1
|
module MIDIMessage
|
4
2
|
|
5
|
-
#
|
6
3
|
# Common Note Message Behavior
|
7
|
-
#
|
8
4
|
module NoteMessage
|
9
5
|
|
10
|
-
|
6
|
+
def self.included(base)
|
7
|
+
base.include(ChannelMessage)
|
8
|
+
end
|
9
|
+
|
10
|
+
# The octave number of the note
|
11
|
+
# @return [Fixnum]
|
11
12
|
def octave
|
12
|
-
(note / 12) -1
|
13
|
+
(note / 12) - 1
|
13
14
|
end
|
14
15
|
alias_method :oct, :octave
|
15
16
|
|
16
|
-
#
|
17
|
-
|
18
|
-
|
17
|
+
# Set the octave number of the note
|
18
|
+
# @param [Fixnum] value
|
19
|
+
# @return [NoteMessage] self
|
20
|
+
def octave=(value)
|
21
|
+
self.note = ((value + 1) * 12) + abs_note
|
19
22
|
self
|
20
23
|
end
|
21
24
|
alias_method :oct=, :octave=
|
22
25
|
|
23
|
-
#
|
26
|
+
# How many half-steps is this note above the closest C
|
27
|
+
# @return [Fixnum]
|
24
28
|
def abs_note
|
25
29
|
note - ((note / 12) * 12)
|
26
30
|
end
|
27
31
|
|
28
|
-
#
|
32
|
+
# The name of the note without its octave e.g. F#
|
33
|
+
# @return [String]
|
29
34
|
def note_name
|
30
35
|
name.split(/-?\d\z/).first
|
31
36
|
end
|
32
37
|
|
33
38
|
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# MIDI Note-Off message
|
37
|
-
#
|
38
|
-
class NoteOff
|
39
|
-
|
40
|
-
include NoteMessage
|
41
|
-
include ShortMessage
|
42
|
-
include ChannelMessage
|
43
|
-
|
44
|
-
schema :channel, :note, :velocity
|
45
|
-
use_display_name 'Note Off'
|
46
|
-
use_constants 'Note', :for => :note
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
#
|
51
|
-
# MIDI Note-On message
|
52
|
-
#
|
53
|
-
class NoteOn
|
54
|
-
|
55
|
-
include NoteMessage
|
56
|
-
include ShortMessage
|
57
|
-
include ChannelMessage
|
58
|
-
|
59
|
-
schema :channel, :note, :velocity
|
60
|
-
use_display_name 'Note On'
|
61
|
-
use_constants 'Note', :for => :note
|
62
|
-
|
63
|
-
# returns the NoteOff equivalent of this object
|
64
|
-
def to_note_off
|
65
|
-
NoteOff.new(channel, note, velocity)
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
39
|
|
70
40
|
end
|