micromidi 0.1.3 → 0.1.4
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 +4 -4
- data/lib/micromidi.rb +5 -5
- data/lib/micromidi/context.rb +38 -19
- data/lib/micromidi/device.rb +37 -0
- data/lib/micromidi/instructions/composite.rb +28 -17
- data/lib/micromidi/instructions/input.rb +81 -38
- data/lib/micromidi/instructions/message.rb +65 -18
- data/lib/micromidi/instructions/output.rb +5 -4
- data/lib/micromidi/instructions/process.rb +53 -9
- data/lib/micromidi/instructions/shorthand.rb +16 -15
- data/lib/micromidi/instructions/sticky.rb +53 -24
- data/lib/micromidi/instructions/sysex.rb +39 -18
- data/lib/micromidi/module_methods.rb +17 -19
- data/lib/micromidi/state.rb +84 -41
- data/lib/midi.rb +6 -5
- data/test/composite_test.rb +23 -28
- data/test/context_test.rb +13 -18
- data/test/effect_test.rb +9 -13
- data/test/helper.rb +16 -9
- data/test/input_test.rb +4 -5
- data/test/message_test.rb +30 -35
- data/test/output_test.rb +3 -8
- data/test/state_test.rb +7 -12
- data/test/sticky_test.rb +37 -42
- data/test/sysex_test.rb +14 -17
- metadata +103 -16
@@ -1,24 +1,36 @@
|
|
1
1
|
module MicroMIDI
|
2
2
|
|
3
3
|
module Instructions
|
4
|
-
|
4
|
+
|
5
|
+
# Commands that deal with MIDI messages
|
5
6
|
class Message
|
6
|
-
|
7
|
+
|
8
|
+
# @param [State] state
|
7
9
|
def initialize(state)
|
8
10
|
@state = state
|
9
11
|
end
|
10
|
-
|
11
|
-
#
|
12
|
+
|
13
|
+
# Create a MIDI control change message
|
14
|
+
# @param [Fixnum, String] id Control name or index
|
15
|
+
# @param [Fixnum] value
|
16
|
+
# @param [Hash] options
|
17
|
+
# @option options [Fixnum] :channel
|
18
|
+
# @return [MIDIMessage::ControlChange]
|
12
19
|
def control_change(id, value, options = {})
|
13
20
|
properties = @state.message_properties(options, :channel)
|
14
|
-
if id.kind_of?(
|
21
|
+
if id.kind_of?(Fixnum)
|
15
22
|
MIDIMessage::ControlChange.new(properties[:channel], id, value)
|
16
23
|
else
|
17
24
|
MIDIMessage::ControlChange[id].new(properties[:channel], value)
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
21
|
-
#
|
28
|
+
# Create a MIDI note on message
|
29
|
+
# @param [Fixnum, String] id Note name or index
|
30
|
+
# @param [Hash] options
|
31
|
+
# @option options [Fixnum] :channel
|
32
|
+
# @option options [Fixnum] :velocity
|
33
|
+
# @return [MIDIMessage::NoteOn]
|
22
34
|
def note(id, options = {})
|
23
35
|
properties = @state.message_properties(options, :channel, :velocity)
|
24
36
|
note = note_message(MIDIMessage::NoteOn, id, properties)
|
@@ -26,38 +38,59 @@ module MicroMIDI
|
|
26
38
|
note
|
27
39
|
end
|
28
40
|
|
29
|
-
#
|
41
|
+
# Create a MIDI note off message
|
42
|
+
# @param [Fixnum, String] id Note name or index
|
43
|
+
# @param [Hash] options
|
44
|
+
# @option options [Fixnum] :channel
|
45
|
+
# @option options [Fixnum] :velocity
|
46
|
+
# @return [MIDIMessage::NoteOff]
|
30
47
|
def note_off(id, options = {})
|
31
48
|
properties = @state.message_properties(options, :channel, :velocity)
|
32
49
|
note_message(MIDIMessage::NoteOff, id, properties)
|
33
50
|
end
|
34
51
|
|
35
|
-
#
|
52
|
+
# Create a MIDI message from raw bytes
|
53
|
+
# @param [Array<Fixnum>, Array<String>, String] message Byte string or array of numeric/string bytes
|
54
|
+
# @return [MIDIMessage]
|
36
55
|
def parse(message)
|
37
56
|
MIDIMessage.parse(message)
|
38
57
|
end
|
39
58
|
|
40
|
-
#
|
59
|
+
# Create a MIDI program change message
|
60
|
+
# @param [Fixnum] program
|
61
|
+
# @param [Hash] options
|
62
|
+
# @option options [Fixnum] :channel
|
63
|
+
# @return [MIDIMessage::ProgramChange]
|
41
64
|
def program_change(program, options = {})
|
42
65
|
properties = @state.message_properties(options, :channel)
|
43
66
|
MIDIMessage::ProgramChange.new(properties[:channel], program)
|
44
67
|
end
|
45
68
|
|
46
|
-
#
|
69
|
+
# Create a MIDI note-off message from the last note-on message
|
70
|
+
# @return [MIDIMessage::NoteOff]
|
47
71
|
def off
|
48
72
|
note_off = @state.last_note.to_note_off unless @state.last_note.nil?
|
49
73
|
@state.last_note = nil
|
50
74
|
note_off
|
51
75
|
end
|
52
|
-
|
53
|
-
#
|
76
|
+
|
77
|
+
# Create a MIDI channel pressure message
|
78
|
+
# @param [Fixnum] value
|
79
|
+
# @param [Hash] options
|
80
|
+
# @option options [Fixnum] :channel
|
81
|
+
# @return [MIDIMessage::ChannelAftertouch]
|
54
82
|
def channel_aftertouch(value, options = {})
|
55
83
|
properties = @state.message_properties(options, :channel)
|
56
84
|
MIDIMessage::ChannelAftertouch.new(properties[:channel], value)
|
57
85
|
end
|
58
86
|
alias_method :channel_pressure, :channel_aftertouch
|
59
|
-
|
60
|
-
#
|
87
|
+
|
88
|
+
# Create a MIDI poly pressure message
|
89
|
+
# @param [Fixnum, String] note
|
90
|
+
# @param [Fixnum] value
|
91
|
+
# @param [Hash] options
|
92
|
+
# @option options [Fixnum] :channel
|
93
|
+
# @return [MIDIMessage::PolyphonicAftertouch]
|
61
94
|
def polyphonic_aftertouch(note, value, options = {})
|
62
95
|
properties = @state.message_properties(options, :channel)
|
63
96
|
MIDIMessage::PolyphonicAftertouch.new(properties[:channel], note, value)
|
@@ -65,16 +98,25 @@ module MicroMIDI
|
|
65
98
|
alias_method :poly_aftertouch, :polyphonic_aftertouch
|
66
99
|
alias_method :polyphonic_pressure, :polyphonic_aftertouch
|
67
100
|
alias_method :poly_pressure, :polyphonic_aftertouch
|
68
|
-
|
101
|
+
|
102
|
+
# Create a MIDI pitch bend message
|
103
|
+
# @param [Fixnum] low
|
104
|
+
# @param [Fixnum] high
|
105
|
+
# @param [Hash] options
|
106
|
+
# @option options [Fixnum] :channel
|
107
|
+
# @return [MIDIMessage::PitchBend]
|
69
108
|
def pitch_bend(low, high, options = {})
|
70
109
|
properties = @state.message_properties(options, :channel)
|
71
110
|
MIDIMessage::PitchBend.new(properties[:channel], low, high)
|
72
111
|
end
|
73
112
|
alias_method :bend, :pitch_bend
|
74
113
|
alias_method :pitchbend, :pitch_bend
|
75
|
-
|
114
|
+
|
76
115
|
protected
|
77
|
-
|
116
|
+
|
117
|
+
# Parse a note name string eg "C4"
|
118
|
+
# @param [String] name
|
119
|
+
# @return [String]
|
78
120
|
def parse_note_name(name)
|
79
121
|
name = name.to_s
|
80
122
|
octave = name.scan(/-?\d\z/).first
|
@@ -86,8 +128,13 @@ module MicroMIDI
|
|
86
128
|
|
87
129
|
private
|
88
130
|
|
131
|
+
# Create a MIDI note on or note off message
|
132
|
+
# @param [Class] klass
|
133
|
+
# @param [Fixnum, String] id
|
134
|
+
# @param [Hash] properties
|
135
|
+
# @return [MIDIMessage::NoteOn, MIDIMessage::NoteOff]
|
89
136
|
def note_message(klass, id, properties)
|
90
|
-
if id.kind_of?(Numeric)
|
137
|
+
if id.kind_of?(Numeric)
|
91
138
|
klass.new(properties[:channel], id, properties[:velocity])
|
92
139
|
elsif id.kind_of?(String) || id.kind_of?(Symbol)
|
93
140
|
note_name = parse_note_name(id)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module MicroMIDI
|
2
2
|
|
3
3
|
module Instructions
|
4
|
-
|
4
|
+
|
5
|
+
# Commands that deal with MIDI output
|
5
6
|
class Output
|
6
|
-
|
7
|
+
|
7
8
|
extend Forwardable
|
8
9
|
|
9
10
|
def_delegators :@state, :toggle_auto_output
|
@@ -16,7 +17,7 @@ module MicroMIDI
|
|
16
17
|
|
17
18
|
# Output a message or toggle the auto output mode
|
18
19
|
# @param [MIDIMessage, Boolean] message A MIDI message to output, or a boolean to toggle auto-output mode
|
19
|
-
# @return [
|
20
|
+
# @return [MIDIMessage]
|
20
21
|
def output(message)
|
21
22
|
set_auto_output(message) if !!message === message # check for boolean
|
22
23
|
unless message.nil?
|
@@ -24,7 +25,7 @@ module MicroMIDI
|
|
24
25
|
end
|
25
26
|
message
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
# Set mode where messages are automatically outputted
|
29
30
|
# @param [Boolean] is_on Whether to set the auto output mode to ON
|
30
31
|
# @return [Boolean]
|
@@ -1,50 +1,94 @@
|
|
1
1
|
module MicroMIDI
|
2
2
|
|
3
3
|
module Instructions
|
4
|
-
|
4
|
+
|
5
|
+
# Commands that deal with processing MIDI messages
|
5
6
|
class Process
|
6
|
-
|
7
|
+
|
8
|
+
# @param [State] state
|
7
9
|
def initialize(state)
|
8
10
|
@state = state
|
9
11
|
end
|
10
|
-
|
12
|
+
|
13
|
+
# Transpose a message value
|
14
|
+
# @param [MIDIMessage] message
|
15
|
+
# @param [Symbol, String] property
|
16
|
+
# @param [Fixnum] factor
|
17
|
+
# @param [Hash] options
|
18
|
+
# @return [MIDIMessage]
|
11
19
|
def transpose(message, property, factor, options = {})
|
12
20
|
MIDIFX.transpose(message, property, factor, options)
|
13
21
|
end
|
14
|
-
|
22
|
+
|
23
|
+
# Limit a message value
|
24
|
+
# @param [MIDIMessage] message
|
25
|
+
# @param [Symbol, String] property
|
26
|
+
# @param [Range] range
|
27
|
+
# @param [Hash] options
|
28
|
+
# @return [MIDIMessage]
|
15
29
|
def limit(message, property, range, options = {})
|
16
30
|
MIDIFX.limit(message, property, range, options)
|
17
31
|
end
|
18
|
-
|
32
|
+
|
33
|
+
# Filter a message value
|
34
|
+
# @param [MIDIMessage] message
|
35
|
+
# @param [Symbol, String] property
|
36
|
+
# @param [Range] bandwidth
|
37
|
+
# @param [Hash] options
|
38
|
+
# @return [MIDIMessage]
|
19
39
|
def filter(message, property, bandwidth, options = {})
|
20
40
|
MIDIFX.filter(message, property, bandwidth, options)
|
21
41
|
end
|
22
|
-
|
42
|
+
|
43
|
+
# High pass filter a message value
|
44
|
+
# @param [MIDIMessage] message
|
45
|
+
# @param [Symbol, String] property
|
46
|
+
# @param [Fixnum] min
|
47
|
+
# @param [Hash] options
|
48
|
+
# @return [MIDIMessage]
|
23
49
|
def high_pass_filter(message, property, min, options = {})
|
24
50
|
MIDIFX.high_pass_filter(message, property, min, options)
|
25
51
|
end
|
26
52
|
alias_method :only_above, :high_pass_filter
|
27
53
|
alias_method :except_below, :high_pass_filter
|
28
54
|
|
55
|
+
# Low pass filter a message value
|
56
|
+
# @param [MIDIMessage] message
|
57
|
+
# @param [Symbol, String] property
|
58
|
+
# @param [Fixnum] max
|
59
|
+
# @param [Hash] options
|
60
|
+
# @return [MIDIMessage]
|
29
61
|
def low_pass_filter(message, property, max, options = {})
|
30
62
|
MIDIFX.low_pass_filter(message, property, max, options)
|
31
63
|
end
|
32
64
|
alias_method :only_below, :low_pass_filter
|
33
65
|
alias_method :except_above, :low_pass_filter
|
34
|
-
|
66
|
+
|
67
|
+
# Band pass filter a message value
|
68
|
+
# @param [MIDIMessage] message
|
69
|
+
# @param [Symbol, String] property
|
70
|
+
# @param [Range] bandwidth
|
71
|
+
# @param [Hash] options
|
72
|
+
# @return [MIDIMessage]
|
35
73
|
def band_pass_filter(message, property, bandwidth, options = {})
|
36
74
|
MIDIFX.band_pass_filter(message, property, bandwidth, options)
|
37
75
|
end
|
38
76
|
alias_method :only_in, :band_pass_filter
|
39
77
|
alias_method :only, :band_pass_filter
|
40
|
-
|
78
|
+
|
79
|
+
# Band reject filter a message value
|
80
|
+
# @param [MIDIMessage] message
|
81
|
+
# @param [Symbol, String] property
|
82
|
+
# @param [Range] bandwidth
|
83
|
+
# @param [Hash] options
|
84
|
+
# @return [MIDIMessage]
|
41
85
|
def notch_filter(message, property, bandwidth, options = {})
|
42
86
|
MIDIFX.notch_filter(message, property, bandwidth, options)
|
43
87
|
end
|
44
88
|
alias_method :band_reject_filter, :notch_filter
|
45
89
|
alias_method :except_in, :notch_filter
|
46
90
|
alias_method :except, :notch_filter
|
47
|
-
|
91
|
+
|
48
92
|
end
|
49
93
|
|
50
94
|
end
|
@@ -1,23 +1,24 @@
|
|
1
1
|
module MicroMIDI
|
2
|
-
|
2
|
+
# Patch shorthand aliases into the MicroMIDI module
|
3
|
+
|
3
4
|
alias l loop
|
4
|
-
|
5
|
+
|
5
6
|
def self.m(*args, &block)
|
6
7
|
send(:message, *args, &block)
|
7
8
|
end
|
8
|
-
|
9
|
+
|
9
10
|
class Context
|
10
11
|
alias_method :r, :repeat
|
11
12
|
end
|
12
|
-
|
13
|
-
module Instructions
|
14
|
-
|
13
|
+
|
14
|
+
module Instructions
|
15
|
+
|
15
16
|
module Composite
|
16
17
|
alias_method :p, :play
|
17
18
|
alias_method :q!, :all_off
|
18
19
|
alias_method :x, :all_off
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
class Input
|
22
23
|
alias_method :j, :join
|
23
24
|
alias_method :rc, :receive
|
@@ -25,9 +26,9 @@ module MicroMIDI
|
|
25
26
|
alias_method :t, :thru
|
26
27
|
alias_method :te, :thru_except
|
27
28
|
alias_method :tu, :thru_unless
|
28
|
-
alias_method :w, :wait_for_input
|
29
|
+
alias_method :w, :wait_for_input
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
class Message
|
32
33
|
alias_method :c, :control_change
|
33
34
|
alias_method :ca, :channel_aftertouch
|
@@ -39,11 +40,11 @@ module MicroMIDI
|
|
39
40
|
alias_method :pb, :pitch_bend
|
40
41
|
alias_method :pc, :program_change
|
41
42
|
end
|
42
|
-
|
43
|
+
|
43
44
|
class Output
|
44
45
|
alias_method :out, :output
|
45
46
|
end
|
46
|
-
|
47
|
+
|
47
48
|
class Process
|
48
49
|
alias_method :bp, :band_pass_filter
|
49
50
|
alias_method :bpf, :band_pass_filter
|
@@ -56,15 +57,15 @@ module MicroMIDI
|
|
56
57
|
alias_method :lpf, :low_pass_filter
|
57
58
|
alias_method :mbf, :filter
|
58
59
|
alias_method :nf, :notch_filter
|
59
|
-
alias_method :tp, :transpose
|
60
|
+
alias_method :tp, :transpose
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
class Sticky
|
63
64
|
alias_method :ch, :channel
|
64
65
|
alias_method :ss, :super_sticky
|
65
66
|
alias_method :v, :velocity
|
66
67
|
end
|
67
|
-
|
68
|
+
|
68
69
|
class SysEx
|
69
70
|
alias_method :sc, :sysex_command
|
70
71
|
alias_method :sr, :sysex_request
|
@@ -75,5 +76,5 @@ module MicroMIDI
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def M(*a, &block)
|
78
|
-
MIDI.message(*a, &block)
|
79
|
+
MIDI.message(*a, &block)
|
79
80
|
end
|
@@ -1,55 +1,84 @@
|
|
1
1
|
module MicroMIDI
|
2
2
|
|
3
3
|
module Instructions
|
4
|
-
|
4
|
+
|
5
|
+
# Commands that deal with sticky default properties.
|
6
|
+
#
|
7
|
+
# For example, setting a default MIDI channel that persists for the messages to follow it:
|
8
|
+
#
|
9
|
+
# ```ruby
|
10
|
+
# channel 5
|
11
|
+
# note "C4"
|
12
|
+
# note "C3"
|
13
|
+
# ```
|
14
|
+
#
|
5
15
|
class Sticky
|
6
|
-
|
16
|
+
|
17
|
+
# @param [State] state
|
7
18
|
def initialize(state)
|
8
19
|
@state = state
|
9
20
|
end
|
10
21
|
|
11
|
-
# sets the sticky channel for the current block
|
12
|
-
|
13
|
-
|
22
|
+
# Gets/sets the sticky channel for the current block
|
23
|
+
# @param [*Fixnum] args args[0] is an optional parameter to set the channel: [Fixnum, nil]
|
24
|
+
# @return [Fixnum]
|
25
|
+
def channel(*args)
|
26
|
+
@state.channel = args.first unless args.empty?
|
27
|
+
@state.channel
|
14
28
|
end
|
15
|
-
|
16
|
-
# sets the octave for the current block
|
17
|
-
|
18
|
-
|
29
|
+
|
30
|
+
# Gets/sets the octave for the current block
|
31
|
+
# @param [*Fixnum] args args[0] is an optional parameter to set the octave: [Fixnum, nil]
|
32
|
+
# @return [Fixnum]
|
33
|
+
def octave(*args)
|
34
|
+
@state.octave = args.first unless args.empty?
|
35
|
+
@state.octave
|
19
36
|
end
|
20
|
-
|
21
|
-
# sets the sysex node for the current block
|
37
|
+
|
38
|
+
# Gets/sets the sysex node for the current block
|
39
|
+
# @param [*Object] args
|
40
|
+
# @return [MIDIMessage::SystemExclusive::Node]
|
22
41
|
def sysex_node(*args)
|
42
|
+
args = args.dup
|
23
43
|
options = args.last.kind_of?(Hash) ? args.last : {}
|
24
|
-
|
44
|
+
@state.sysex_node = MIDIMessage::SystemExclusive::Node.new(args.first, options) unless args.empty?
|
45
|
+
@state.sysex_node
|
25
46
|
end
|
26
47
|
alias_method :node, :sysex_node
|
27
48
|
|
28
|
-
# sets the sticky velocity for the current block
|
29
|
-
|
30
|
-
|
49
|
+
# Gets/sets the sticky velocity for the current block
|
50
|
+
# @param [*Fixnum] args args[0] is an optional parameter to set the velocity: [Fixnum, nil]
|
51
|
+
# @return [Fixnum]
|
52
|
+
def velocity(*args)
|
53
|
+
@state.velocity = args.first unless args.empty?
|
54
|
+
@state.velocity
|
31
55
|
end
|
32
|
-
|
56
|
+
|
33
57
|
#
|
34
|
-
#
|
35
|
-
# automatically become sticky
|
58
|
+
# Toggles super_sticky mode, a mode where any explicit values used to create MIDI messages
|
59
|
+
# automatically become sticky. Normally the explicit value would only be used for
|
36
60
|
# the current message.
|
37
61
|
#
|
38
|
-
#
|
62
|
+
# For example, while in super sticky mode
|
39
63
|
#
|
64
|
+
# ```ruby
|
40
65
|
# note "C4", :channel => 5
|
66
|
+
# note "C3"
|
67
|
+
# ```
|
68
|
+
#
|
69
|
+
# will have the same results as
|
41
70
|
#
|
42
|
-
#
|
43
|
-
#
|
71
|
+
# ```ruby
|
44
72
|
# channel 5
|
45
73
|
# note "C4"
|
74
|
+
# note "C3"
|
75
|
+
# ```
|
46
76
|
#
|
47
|
-
#
|
48
|
-
#
|
77
|
+
# @return [Boolean]
|
49
78
|
def super_sticky
|
50
79
|
@state.toggle_super_sticky
|
51
80
|
end
|
52
|
-
|
81
|
+
|
53
82
|
end
|
54
83
|
|
55
84
|
end
|