midi-message 0.2.4 → 0.3.0
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/lib/midi-message.rb +18 -15
- data/lib/midi-message/event/note.rb +31 -0
- data/lib/midi-message/process/filter.rb +15 -15
- data/lib/midi-message/process/limit.rb +15 -10
- data/lib/midi-message/process/processor.rb +13 -5
- data/lib/midi-message/process/transpose.rb +7 -7
- data/test/test_filter.rb +12 -12
- data/test/test_limit.rb +11 -4
- data/test/test_note_event.rb +32 -0
- data/test/test_transpose.rb +4 -4
- metadata +4 -2
data/lib/midi-message.rb
CHANGED
@@ -5,33 +5,36 @@
|
|
5
5
|
#
|
6
6
|
module MIDIMessage
|
7
7
|
|
8
|
+
module Event
|
9
|
+
end
|
10
|
+
|
8
11
|
module Process
|
9
12
|
end
|
10
13
|
|
11
|
-
VERSION = "0.
|
14
|
+
VERSION = "0.3.0"
|
12
15
|
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
require 'midi-message/short_message'
|
20
|
-
require 'midi-message/channel_message'
|
21
|
-
require 'midi-message/constant'
|
22
|
-
require 'midi-message/context'
|
23
|
-
require 'midi-message/note_message'
|
24
|
-
require 'midi-message/parser'
|
25
|
-
require 'midi-message/system_message'
|
26
|
-
require 'midi-message/system_exclusive'
|
27
|
-
require 'midi-message/type_conversion'
|
18
|
+
# libs
|
19
|
+
require "forwardable"
|
20
|
+
require "yaml"
|
28
21
|
|
29
|
-
#
|
22
|
+
# messages (mixed format)
|
23
|
+
require "midi-message/short_message"
|
24
|
+
require "midi-message/channel_message"
|
25
|
+
require "midi-message/constant"
|
26
|
+
require "midi-message/context"
|
27
|
+
require "midi-message/note_message"
|
28
|
+
require "midi-message/parser"
|
29
|
+
require "midi-message/system_message"
|
30
|
+
require "midi-message/system_exclusive"
|
31
|
+
require "midi-message/type_conversion"
|
30
32
|
|
31
33
|
# modules
|
32
34
|
require "midi-message/process/processor"
|
33
35
|
|
34
36
|
# classes
|
37
|
+
require "midi-message/event/note"
|
35
38
|
require "midi-message/process/filter"
|
36
39
|
require "midi-message/process/limit"
|
37
40
|
require "midi-message/process/transpose"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
module MIDIMessage
|
3
|
+
|
4
|
+
module Event
|
5
|
+
|
6
|
+
# an Event::Note is a pairing of a MIDI NoteOn and NoteOff message
|
7
|
+
# has a length that corresponds to sequencer ticks
|
8
|
+
class Note
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
attr_reader :start,
|
13
|
+
:finish,
|
14
|
+
:length
|
15
|
+
|
16
|
+
alias_method :duration, :length
|
17
|
+
|
18
|
+
def_delegators :start, :note
|
19
|
+
|
20
|
+
def initialize(start_message, duration, options = {})
|
21
|
+
@start = start_message
|
22
|
+
@length = duration
|
23
|
+
|
24
|
+
@finish = options[:finish] || start_message.to_note_off
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -11,45 +11,45 @@ module MIDIMessage
|
|
11
11
|
|
12
12
|
attr_reader :bandwidth, :property, :reject
|
13
13
|
|
14
|
-
def initialize(
|
14
|
+
def initialize(prop, bandwidth, options = {})
|
15
15
|
@bandwidth = [bandwidth].flatten
|
16
|
-
@message = message
|
17
16
|
@property = prop
|
18
17
|
@reject = options[:reject] || false
|
19
|
-
|
18
|
+
|
19
|
+
initialize_processor(options)
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
val =
|
24
|
-
result = @bandwidth.map { |bw| val >= bw.min && val <= bw.max ?
|
25
|
-
result.include?(
|
22
|
+
def process_single(message)
|
23
|
+
val = message.send(@property)
|
24
|
+
result = @bandwidth.map { |bw| val >= bw.min && val <= bw.max ? message : nil }
|
25
|
+
result.include?(message) ^ @reject ? message : nil
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
29
29
|
|
30
30
|
class LowPassFilter < Filter
|
31
|
-
def initialize(
|
32
|
-
super(
|
31
|
+
def initialize(prop, max, options = {})
|
32
|
+
super(prop, (0..max), options)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
class HighPassFilter < Filter
|
37
|
-
def initialize(
|
38
|
-
super(
|
37
|
+
def initialize(prop, min, options = {})
|
38
|
+
super(prop, (min..127), options)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
class BandPassFilter < Filter
|
43
|
-
def initialize(
|
43
|
+
def initialize(prop, accept_range, options = {})
|
44
44
|
options[:reject] = false
|
45
|
-
super(
|
45
|
+
super(prop, accept_range, options)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
class BandRejectFilter < Filter
|
50
|
-
def initialize(
|
50
|
+
def initialize(prop, reject_range, options = {})
|
51
51
|
options[:reject] = true
|
52
|
-
super(
|
52
|
+
super(prop, reject_range, options)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
NotchFilter = BandRejectFilter
|
@@ -8,20 +8,25 @@ module MIDIMessage
|
|
8
8
|
|
9
9
|
include Processor
|
10
10
|
|
11
|
-
attr_reader :property, :
|
11
|
+
attr_reader :property, :limit_to
|
12
|
+
alias_method :range, :limit_to
|
12
13
|
|
13
|
-
def initialize(
|
14
|
-
@
|
15
|
-
@message = message
|
14
|
+
def initialize(prop, limit_to, options = {})
|
15
|
+
@limit_to = limit_to
|
16
16
|
@property = prop
|
17
|
-
|
17
|
+
|
18
|
+
initialize_processor(options)
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
val =
|
22
|
-
@
|
23
|
-
|
24
|
-
|
21
|
+
def process_single(message)
|
22
|
+
val = message.send(@property)
|
23
|
+
if @limit_to.kind_of?(Range)
|
24
|
+
message.send("#{@property}=", @limit_to.min) if val < @limit_to.min
|
25
|
+
message.send("#{@property}=", @limit_to.max) if val > @limit_to.max
|
26
|
+
elsif @limit_to.kind_of?(Numeric)
|
27
|
+
message.send("#{@property}=", @limit_to)
|
28
|
+
end
|
29
|
+
message
|
25
30
|
end
|
26
31
|
|
27
32
|
end
|
@@ -8,19 +8,27 @@ module MIDIMessage
|
|
8
8
|
|
9
9
|
def self.included(base)
|
10
10
|
base.extend(ClassMethods)
|
11
|
-
base.send(:attr_reader, :message)
|
11
|
+
#base.send(:attr_reader, :message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def process(messages = nil)
|
15
|
+
messages = @message unless @message.nil?
|
16
|
+
result = [messages].flatten.map { |message| process_single(message) }
|
17
|
+
result.kind_of?(Array) && result.size == 1 ? result.first : result
|
12
18
|
end
|
13
19
|
|
14
20
|
module ClassMethods
|
15
|
-
|
16
|
-
|
21
|
+
|
22
|
+
def process(msg, *a, &block)
|
23
|
+
new(*a).process(msg, &block)
|
17
24
|
end
|
25
|
+
|
18
26
|
end
|
19
27
|
|
20
28
|
private
|
21
29
|
|
22
|
-
def initialize_processor(
|
23
|
-
@message = message
|
30
|
+
def initialize_processor(options)
|
31
|
+
@message = options[:message]
|
24
32
|
end
|
25
33
|
|
26
34
|
end
|
@@ -10,17 +10,17 @@ module MIDIMessage
|
|
10
10
|
|
11
11
|
attr_reader :factor, :property
|
12
12
|
|
13
|
-
def initialize(
|
13
|
+
def initialize(prop, factor, options = {})
|
14
14
|
@factor = factor
|
15
|
-
@message = message
|
16
15
|
@property = prop
|
17
|
-
|
16
|
+
|
17
|
+
initialize_processor(options)
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
val =
|
22
|
-
|
23
|
-
|
20
|
+
def process_single(message)
|
21
|
+
val = message.send(@property)
|
22
|
+
message.send("#{@property}=", val + @factor)
|
23
|
+
message
|
24
24
|
end
|
25
25
|
|
26
26
|
end
|
data/test/test_filter.rb
CHANGED
@@ -11,84 +11,84 @@ class FilterTest < Test::Unit::TestCase
|
|
11
11
|
def test_high_pass_note_reject
|
12
12
|
msg = MIDIMessage::NoteOn["C0"].new(0, 100)
|
13
13
|
assert_equal(12, msg.note)
|
14
|
-
outp = HighPassFilter.new(
|
14
|
+
outp = HighPassFilter.new(:note, 20).process(msg)
|
15
15
|
assert_equal(nil, outp)
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_high_pass_note_accept
|
19
19
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
20
20
|
assert_equal(60, msg.note)
|
21
|
-
outp = HighPassFilter.new(
|
21
|
+
outp = HighPassFilter.new(:note, 20).process(msg)
|
22
22
|
assert_equal(msg, outp)
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_low_pass_note_reject
|
26
26
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
27
27
|
assert_equal(60, msg.note)
|
28
|
-
outp = LowPassFilter.new(
|
28
|
+
outp = LowPassFilter.new(:note, 50).process(msg)
|
29
29
|
assert_equal(nil, outp)
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_low_pass_note_accept
|
33
33
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
34
34
|
assert_equal(60, msg.note)
|
35
|
-
outp = LowPassFilter.new(
|
35
|
+
outp = LowPassFilter.new(:note, 100).process(msg)
|
36
36
|
assert_equal(msg, outp)
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_band_pass_note_reject
|
40
40
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
41
41
|
assert_equal(60, msg.note)
|
42
|
-
outp = BandPassFilter.new(
|
42
|
+
outp = BandPassFilter.new(:note, (20..50)).process(msg)
|
43
43
|
assert_equal(nil, outp)
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_band_pass_note_accept
|
47
47
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
48
48
|
assert_equal(60, msg.note)
|
49
|
-
outp = BandPassFilter.new(
|
49
|
+
outp = BandPassFilter.new(:note, (20..100)).process(msg)
|
50
50
|
assert_equal(msg, outp)
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_band_reject_note_reject
|
54
54
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
55
55
|
assert_equal(60, msg.note)
|
56
|
-
outp = NotchFilter.new(
|
56
|
+
outp = NotchFilter.new(:note, (20..70)).process(msg)
|
57
57
|
assert_equal(nil, outp)
|
58
58
|
end
|
59
59
|
|
60
60
|
def test_band_reject_note_accept
|
61
61
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
62
62
|
assert_equal(60, msg.note)
|
63
|
-
outp = NotchFilter.new(
|
63
|
+
outp = NotchFilter.new(:note, (20..50)).process(msg)
|
64
64
|
assert_equal(msg, outp)
|
65
65
|
end
|
66
66
|
|
67
67
|
def test_multiband_note_reject
|
68
68
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
69
69
|
assert_equal(60, msg.note)
|
70
|
-
outp = Filter.new(
|
70
|
+
outp = Filter.new(:note, [(20..30), (40..50)]).process(msg)
|
71
71
|
assert_equal(nil, outp)
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_multiband_note_accept
|
75
75
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
76
76
|
assert_equal(60, msg.note)
|
77
|
-
outp = Filter.new(
|
77
|
+
outp = Filter.new(:note, [(20..30), (50..70)]).process(msg)
|
78
78
|
assert_equal(msg, outp)
|
79
79
|
end
|
80
80
|
|
81
81
|
def test_multinotch_note_reject
|
82
82
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
83
83
|
assert_equal(60, msg.note)
|
84
|
-
outp = Filter.new(
|
84
|
+
outp = Filter.new(:note, [(20..30), (55..65)], :reject => true).process(msg)
|
85
85
|
assert_equal(nil, outp)
|
86
86
|
end
|
87
87
|
|
88
88
|
def test_multinotch_note_accept
|
89
89
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
90
90
|
assert_equal(60, msg.note)
|
91
|
-
outp = Filter.new(
|
91
|
+
outp = Filter.new(:note, [(20..30), (40..50)], :reject => true).process(msg)
|
92
92
|
assert_equal(msg, outp)
|
93
93
|
end
|
94
94
|
|
data/test/test_limit.rb
CHANGED
@@ -7,32 +7,39 @@ class LimitTest < Test::Unit::TestCase
|
|
7
7
|
include MIDIMessage
|
8
8
|
include MIDIMessage::Process
|
9
9
|
include TestHelper
|
10
|
+
|
11
|
+
def test_numeric_range
|
12
|
+
msg = MIDIMessage::NoteOn["C0"].new(0, 100)
|
13
|
+
assert_equal(12, msg.note)
|
14
|
+
Limit.new(:note, 30).process(msg)
|
15
|
+
assert_equal(30, msg.note)
|
16
|
+
end
|
10
17
|
|
11
18
|
def test_low_note
|
12
19
|
msg = MIDIMessage::NoteOn["C0"].new(0, 100)
|
13
20
|
assert_equal(12, msg.note)
|
14
|
-
Limit.new(
|
21
|
+
Limit.new(:note, (20..50)).process(msg)
|
15
22
|
assert_equal(20, msg.note)
|
16
23
|
end
|
17
24
|
|
18
25
|
def test_high_note
|
19
26
|
msg = MIDIMessage::NoteOn["C6"].new(0, 100)
|
20
27
|
assert_equal(84, msg.note)
|
21
|
-
Limit.new(
|
28
|
+
Limit.new(:note, (20..50)).process(msg)
|
22
29
|
assert_equal(50, msg.note)
|
23
30
|
end
|
24
31
|
|
25
32
|
def test_low_velocity
|
26
33
|
msg = MIDIMessage::NoteOn["C0"].new(0, 10)
|
27
34
|
assert_equal(10, msg.velocity)
|
28
|
-
Limit.new(
|
35
|
+
Limit.new(:velocity, (30..110)).process(msg)
|
29
36
|
assert_equal(30, msg.velocity)
|
30
37
|
end
|
31
38
|
|
32
39
|
def test_high_velocity
|
33
40
|
msg = MIDIMessage::NoteOn["C6"].new(0, 120)
|
34
41
|
assert_equal(120, msg.velocity)
|
35
|
-
Limit.new(
|
42
|
+
Limit.new(:velocity, (25..75)).process(msg)
|
36
43
|
assert_equal(75, msg.velocity)
|
37
44
|
end
|
38
45
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class NoteEventTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include MIDIMessage
|
8
|
+
include TestHelper
|
9
|
+
|
10
|
+
def test_create_event
|
11
|
+
msg = NoteOn.new(0, 0x40, 0x40)
|
12
|
+
event = Event::Note.new(msg, 10)
|
13
|
+
assert_equal(msg, event.start)
|
14
|
+
assert_equal(10, event.duration)
|
15
|
+
assert_equal(NoteOff, event.finish.class)
|
16
|
+
assert_equal(msg.note, event.finish.note)
|
17
|
+
assert_equal(msg.note, event.note)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_override_finish
|
21
|
+
msg = NoteOn.new(0, 0x40, 0x40)
|
22
|
+
msg2 = NoteOff.new(0, 0x40, 127)
|
23
|
+
event = Event::Note.new(msg, 5, :finish => msg2)
|
24
|
+
assert_equal(msg, event.start)
|
25
|
+
assert_equal(5, event.duration)
|
26
|
+
assert_equal(0x40, event.start.velocity)
|
27
|
+
assert_equal(NoteOff, event.finish.class)
|
28
|
+
assert_equal(0x40, event.finish.note)
|
29
|
+
assert_equal(127, event.finish.velocity)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/test/test_transpose.rb
CHANGED
@@ -11,28 +11,28 @@ class TransposeTest < Test::Unit::TestCase
|
|
11
11
|
def test_transpose_note_up
|
12
12
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
13
13
|
assert_equal(60, msg.note)
|
14
|
-
Transpose.new(
|
14
|
+
Transpose.new(:note, 5).process(msg)
|
15
15
|
assert_equal(65, msg.note)
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_transpose_velocity_up
|
19
19
|
msg = MIDIMessage::NoteOn["C4"].new(0, 82)
|
20
20
|
assert_equal(82, msg.velocity)
|
21
|
-
Transpose.new(
|
21
|
+
Transpose.new(:velocity, 10).process(msg)
|
22
22
|
assert_equal(92, msg.velocity)
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_transpose_note_down
|
26
26
|
msg = MIDIMessage::NoteOn["C4"].new(0, 100)
|
27
27
|
assert_equal(60, msg.note)
|
28
|
-
Transpose.new(
|
28
|
+
Transpose.new(:note, -5).process(msg)
|
29
29
|
assert_equal(55, msg.note)
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_transpose_velocity_down
|
33
33
|
msg = MIDIMessage::NoteOn["C4"].new(0, 82)
|
34
34
|
assert_equal(82, msg.velocity)
|
35
|
-
Transpose.new(
|
35
|
+
Transpose.new(:velocity, -10).process(msg)
|
36
36
|
assert_equal(72, msg.velocity)
|
37
37
|
end
|
38
38
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: midi-message
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
12
|
+
date: 2011-09-27 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description: MIDI messages, objectified in Ruby
|
15
15
|
email:
|
@@ -21,6 +21,7 @@ files:
|
|
21
21
|
- lib/midi-message/channel_message.rb
|
22
22
|
- lib/midi-message/constant.rb
|
23
23
|
- lib/midi-message/context.rb
|
24
|
+
- lib/midi-message/event/note.rb
|
24
25
|
- lib/midi-message/note_message.rb
|
25
26
|
- lib/midi-message/parser.rb
|
26
27
|
- lib/midi-message/process/filter.rb
|
@@ -39,6 +40,7 @@ files:
|
|
39
40
|
- test/test_filter.rb
|
40
41
|
- test/test_limit.rb
|
41
42
|
- test/test_mutability.rb
|
43
|
+
- test/test_note_event.rb
|
42
44
|
- test/test_parser.rb
|
43
45
|
- test/test_processor.rb
|
44
46
|
- test/test_short_message.rb
|