midi-message 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|