midi-nibbler 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module Nibbler
2
-
2
+
3
3
  # A parser session
4
4
  #
5
5
  # Holds on to data that is not relevant to the parser between calls. For instance,
@@ -12,26 +12,28 @@ module Nibbler
12
12
  attr_reader :messages,
13
13
  :processed,
14
14
  :rejected
15
-
16
- def_delegators :@parser, :buffer
15
+
16
+ def_delegators :@parser, :buffer
17
17
  def_delegator :clear_buffer, :buffer, :clear
18
18
  def_delegator :clear_processed, :processed, :clear
19
19
  def_delegator :clear_rejected, :rejected, :clear
20
20
  def_delegator :clear_messages, :messages, :clear
21
21
 
22
22
  # @param [Hash] options
23
+ # @option options [Symbol] :message_lib The name of a message library module eg MIDIMessage or Midilib
23
24
  # @option options [Boolean] :timestamps Whether to report timestamps
24
25
  def initialize(options = {})
25
26
  @timestamps = options[:timestamps] || false
26
27
  @callbacks, @processed, @rejected, @messages = [], [], [], []
27
- @parser = Parser.new(options)
28
+ @library = MessageLibrary.adapter(options[:message_lib])
29
+ @parser = Parser.new(@library)
28
30
  end
29
-
31
+
30
32
  # @return [Array<Object>]
31
33
  def all_messages
32
34
  @messages | @fragmented_messages
33
35
  end
34
-
36
+
35
37
  # The buffer as a single hex string
36
38
  # @return [String]
37
39
  def buffer_s
@@ -48,13 +50,13 @@ module Nibbler
48
50
  def clear_messages
49
51
  @messages.clear
50
52
  end
51
-
53
+
52
54
  # Convert messages to hashes with timestamps
53
55
  def use_timestamps
54
56
  if !@timestamps
55
57
  @messages = @messages.map do |message|
56
- {
57
- :messages => message,
58
+ {
59
+ :messages => message,
58
60
  :timestamp => nil
59
61
  }
60
62
  end
@@ -71,19 +73,19 @@ module Nibbler
71
73
  options = args.last.kind_of?(Hash) ? args.pop : {}
72
74
  timestamp = options[:timestamp]
73
75
 
74
- use_timestamps if !timestamp.nil?
76
+ use_timestamps if !timestamp.nil?
75
77
 
76
78
  result = process(args)
77
- log(result, timestamp)
78
- end
79
-
79
+ log(result, timestamp)
80
+ end
81
+
80
82
  private
81
83
 
82
84
  # Process the input
83
85
  # @param [Array<Object>] input
84
86
  # @return [Hash]
85
87
  def process(input)
86
- queue = HexProcessor.process(input)
88
+ queue = DataProcessor.process(input)
87
89
  @parser.process(queue)
88
90
  end
89
91
 
@@ -96,16 +98,16 @@ module Nibbler
96
98
  @rejected += parser_report[:rejected]
97
99
  get_output(num)
98
100
  end
99
-
101
+
100
102
  # @param [Array<Object>] messages The MIDI messages to log
101
- # @return [Fixnum] The number of MIDI messages logged
103
+ # @return [Integer] The number of MIDI messages logged
102
104
  def log_message(messages, options = {})
103
105
  if @timestamps
104
106
  messages_for_log = messages.count == 1 ? messages.first : messages
105
- @messages << {
106
- :messages => messages_for_log,
107
- :timestamp => options[:timestamp]
108
- }
107
+ @messages << {
108
+ :messages => messages_for_log,
109
+ :timestamp => options[:timestamp]
110
+ }
109
111
  else
110
112
  @messages += messages
111
113
  end
@@ -122,13 +124,13 @@ module Nibbler
122
124
  # 1 message: the message
123
125
  # >1 message: an array of messages
124
126
  #
125
- # @param [Fixnum] num The number of new messages to report
126
- # @return [Array<Object>, Hash]
127
+ # @param [Integer] num The number of new messages to report
128
+ # @return [Array<Object>, Hash]
127
129
  def get_output(num)
128
130
  messages = @messages.last(num)
129
- messages.count < 2 ? messages.first : messages
131
+ messages.count < 2 ? messages.first : messages
130
132
  end
131
-
133
+
132
134
  end
133
-
135
+
134
136
  end
@@ -1,40 +1,76 @@
1
1
  module Nibbler
2
-
2
+
3
3
  # A helper for converting between different types of nibbles and bytes
4
4
  module TypeConversion
5
5
 
6
6
  extend self
7
-
7
+
8
8
  # Converts an array of hex nibble strings to numeric bytes
9
+ # eg ["9", "0", "5", "0", "4", "0"] => [0x90, 0x50, 0x40]
9
10
  # @param [Array<String>] nibbles
10
- # @return [Array<Fixnum>]
11
+ # @return [Array<Integer>]
11
12
  def hex_chars_to_numeric_bytes(nibbles)
12
13
  nibbles = nibbles.dup
13
14
  # get rid of last nibble if there's an odd number
14
15
  # it will be processed later anyway
15
16
  nibbles.slice!(nibbles.length-2, 1) if nibbles.length.odd?
16
17
  bytes = []
17
- while !(nibs = nibbles.slice!(0,2)).empty?
18
+ until (nibs = nibbles.slice!(0,2)).empty?
18
19
  byte = (nibs[0].hex << 4) + nibs[1].hex
19
20
  bytes << byte
20
21
  end
21
22
  bytes
22
23
  end
23
-
24
+
24
25
  # Converts a string of hex digits to string nibbles
26
+ # eg "905040" => ["9", "0", "5", "0", "4", "0"]
25
27
  # @param [String] string
26
28
  # @return [Array<String>]
27
29
  def hex_str_to_hex_chars(string)
28
- string.split(//)
30
+ string.split(//)
31
+ end
32
+
33
+ # Converts a string of hex digits to numeric nibbles
34
+ # eg "905040" => [0x9, 0x0, 0x5, 0x0, 0x4, 0x0]
35
+ # @param [String] string
36
+ # @return [Array<String>]
37
+ def hex_str_to_numeric_nibbles(string)
38
+ bytes = hex_str_to_numeric_bytes(string)
39
+ numeric_bytes_to_numeric_nibbles(bytes)
40
+ end
41
+
42
+ # Converts a string of hex digits to numeric bytes
43
+ # eg "905040" => [0x90, 0x50, 0x40]
44
+ # @param [String] string
45
+ # @return [Array<String>]
46
+ def hex_str_to_numeric_bytes(string)
47
+ chars = hex_str_to_hex_chars(string)
48
+ hex_chars_to_numeric_bytes(chars)
49
+ end
50
+
51
+ # Converts an array bytes to an array of nibbles
52
+ # eg [0x90, 0x50, 0x40] => [0x9, 0x0, 0x5, 0x0, 0x4, 0x0]
53
+ # @param [String] string
54
+ # @return [Array<String>]
55
+ def numeric_bytes_to_numeric_nibbles(bytes)
56
+ bytes.map { |byte| numeric_byte_to_numeric_nibbles(byte) }.flatten
29
57
  end
30
-
31
- # Converts a numeric byte to an array of hex nibble strings
32
- # @param [Fixnum] num
58
+
59
+ # Converts a numeric byte to an array of hex nibble strings eg 0x90 => ["9", "0"]
60
+ # @param [Integer] num
33
61
  # @return [Array<String>]
34
62
  def numeric_byte_to_hex_chars(num)
35
- [((num & 0xF0) >> 4), (num & 0x0F)].map { |n| n.to_s(16) }
63
+ nibbles = numeric_byte_to_numeric_nibbles(num)
64
+ nibbles.map { |n| n.to_s(16) }
65
+ end
66
+
67
+ # Converts a numeric byte to an array of numeric nibbles eg 0x90 => [0x9, 0x0]
68
+ # @param [Integer] num
69
+ # @return [Array<String>]
70
+ def numeric_byte_to_numeric_nibbles(num)
71
+ [((num & 0xF0) >> 4), (num & 0x0F)]
36
72
  end
37
73
 
38
74
  end
39
-
75
+
40
76
  end
@@ -0,0 +1,146 @@
1
+ require "helper"
2
+
3
+ class Nibbler::DataProcessorTest < Minitest::Test
4
+
5
+ context "DataProcessor" do
6
+
7
+ setup do
8
+ @processor = Nibbler::DataProcessor
9
+ end
10
+
11
+ context "#process" do
12
+
13
+ context "string" do
14
+
15
+ setup do
16
+ @str = "904050"
17
+ @nibbles = @processor.send(:process, @str)
18
+ end
19
+
20
+ should "not alter input" do
21
+ assert_equal("904050", @str)
22
+ end
23
+
24
+ should "return correct nibbles" do
25
+ assert_equal(["9", "0", "4", "0", "5", "0"], @nibbles)
26
+ end
27
+
28
+ end
29
+
30
+ context "numeric" do
31
+
32
+ setup do
33
+ @num = 0x90
34
+ @nibbles = @processor.send(:process, @num)
35
+ end
36
+
37
+ should "not alter input" do
38
+ assert_equal(0x90, @num)
39
+ end
40
+
41
+ should "return correct nibbles" do
42
+ assert_equal(["9", "0"], @nibbles)
43
+ end
44
+
45
+ end
46
+
47
+ context "mixed types" do
48
+
49
+ setup do
50
+ @array = [0x90, "90", "9"]
51
+ end
52
+
53
+ context "normal" do
54
+
55
+ setup do
56
+ @nibbles = @processor.send(:process, @array)
57
+ end
58
+
59
+ should "not alter input" do
60
+ assert_equal([0x90, "90", "9"], @array)
61
+ end
62
+
63
+ should "return correct nibbles" do
64
+ assert_equal(["9", "0", "9", "0", "9"], @nibbles)
65
+ end
66
+
67
+ end
68
+
69
+ context "splatted" do
70
+
71
+ setup do
72
+ @nibbles = @processor.send(:process, *@array)
73
+ end
74
+
75
+ should "not alter input" do
76
+ assert_equal([0x90, "90", "9"], @array)
77
+ end
78
+
79
+ should "return correct nibbles" do
80
+ assert_equal(["9", "0", "9", "0", "9"], @nibbles)
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ context "#filter_numeric" do
90
+
91
+ context "filtered" do
92
+
93
+ setup do
94
+ @num = 560
95
+ @result = @processor.send(:filter_numeric, @num)
96
+ end
97
+
98
+ should "not alter input" do
99
+ assert_equal(560, @num)
100
+ end
101
+
102
+ should "return nil" do
103
+ assert_nil @result
104
+ end
105
+
106
+ end
107
+
108
+ context "passing" do
109
+
110
+ setup do
111
+ @num = 50
112
+ @result = @processor.send(:filter_numeric, @num)
113
+ end
114
+
115
+ should "not alter input" do
116
+ assert_equal(50, @num)
117
+ end
118
+
119
+ should "return number" do
120
+ assert_equal(50, @result)
121
+ end
122
+
123
+ end
124
+
125
+ end
126
+
127
+ context "#filter_string" do
128
+
129
+ setup do
130
+ @input = "(0xAdjskla#(#"
131
+ @result = @processor.send(:filter_string, @input)
132
+ end
133
+
134
+ should "not alter input" do
135
+ assert_equal("(0xAdjskla#(#", @input)
136
+ end
137
+
138
+ should "return valid chars" do
139
+ assert_equal("0ADA", @result)
140
+ end
141
+
142
+ end
143
+
144
+ end
145
+
146
+ end
@@ -0,0 +1,64 @@
1
+ require "helper"
2
+
3
+ class Nibbler::FunctionalBufferTest < Minitest::Test
4
+
5
+ context "Parser::Buffer" do
6
+
7
+ setup do
8
+ @nibbler = Nibbler.new
9
+ end
10
+
11
+ should "have processed string nibble" do
12
+ @nibbler.parse("9")
13
+ assert_equal(["9"], @nibbler.buffer)
14
+ end
15
+
16
+ should "have processed numeric byte" do
17
+ @nibbler.parse(0x90)
18
+ assert_equal(["9", "0"], @nibbler.buffer)
19
+ end
20
+
21
+ should "have processed string byte" do
22
+ @nibbler.parse("90")
23
+ assert_equal(["9", "0"], @nibbler.buffer)
24
+ end
25
+
26
+ should "have processed array" do
27
+ @nibbler.parse([0x90])
28
+ assert_equal(["9", "0"], @nibbler.buffer)
29
+ end
30
+
31
+ should "have processed numeric bytes" do
32
+ @nibbler.parse(0x90, 0x40)
33
+ assert_equal(["9", "0", "4", "0"], @nibbler.buffer)
34
+ end
35
+
36
+ should "have processed string bytes" do
37
+ @nibbler.parse("90", "40")
38
+ assert_equal(["9", "0", "4", "0"], @nibbler.buffer)
39
+ end
40
+
41
+ should "have processed two-byte string" do
42
+ @nibbler.parse("9040")
43
+ assert_equal(["9", "0", "4", "0"], @nibbler.buffer)
44
+ end
45
+
46
+ should "have processed mixed bytes" do
47
+ @nibbler.parse("90", 0x40)
48
+ assert_equal(["9", "0", "4", "0"], @nibbler.buffer)
49
+ end
50
+
51
+ should "have processed mixed nibble and byte" do
52
+ @nibbler.parse("9", 0x40)
53
+ assert_equal(["9", "4", "0"], @nibbler.buffer)
54
+ end
55
+
56
+ should "have processed separate data" do
57
+ @nibbler.parse("9")
58
+ @nibbler.parse(0x40)
59
+ assert_equal(["9", "4", "0"], @nibbler.buffer)
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,154 @@
1
+ require "helper"
2
+
3
+ class Nibbler::FunctionalRejectedTest < Minitest::Test
4
+
5
+ context "Rejected" do
6
+
7
+ setup do
8
+ @nibbler = Nibbler.new
9
+ end
10
+
11
+ context "leading chars" do
12
+
13
+ setup do
14
+ @message = @nibbler.parse("0", "9", "04", "040")
15
+ end
16
+
17
+ should "return correct message" do
18
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
19
+ end
20
+
21
+ should "reject extra char" do
22
+ refute_empty @nibbler.rejected
23
+ assert_equal("0", @nibbler.rejected.first)
24
+ end
25
+
26
+ end
27
+
28
+ context "2 leading chars" do
29
+
30
+ setup do
31
+ @message = @nibbler.parse("1", "0", "9", "04", "040")
32
+ end
33
+
34
+ should "reject two leading chars" do
35
+ refute_empty @nibbler.rejected
36
+ assert_equal "1", @nibbler.rejected[0]
37
+ assert_equal "0", @nibbler.rejected[1]
38
+ end
39
+
40
+ end
41
+
42
+ context "leading string" do
43
+
44
+ setup do
45
+ @message = @nibbler.parse("10", "9", "04", "040")
46
+ end
47
+
48
+ should "return correct message" do
49
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
50
+ end
51
+
52
+ should "reject chars in leading string" do
53
+ refute_empty @nibbler.rejected
54
+ assert_equal "1", @nibbler.rejected[0]
55
+ assert_equal "0", @nibbler.rejected[1]
56
+ end
57
+
58
+ end
59
+
60
+ context "long leading string" do
61
+
62
+ setup do
63
+ @message = @nibbler.parse("000001000010", "9", "04", "040")
64
+ end
65
+
66
+ should "return correct message" do
67
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
68
+ end
69
+
70
+ should "return string" do
71
+ refute_empty @nibbler.rejected
72
+ assert_equal("000001000010".split(//), @nibbler.rejected)
73
+ end
74
+
75
+ end
76
+
77
+ context "long leading string overlap" do
78
+
79
+ setup do
80
+ @message = @nibbler.parse("000001000010090", "4", "040")
81
+ end
82
+
83
+ should "return correct message" do
84
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
85
+ end
86
+
87
+ should "return leading string" do
88
+ refute_empty @nibbler.rejected
89
+ assert_equal("0000010000100".split(//), @nibbler.rejected)
90
+ end
91
+
92
+ end
93
+
94
+ context "leading number" do
95
+
96
+ setup do
97
+ @message = @nibbler.parse(0x30, "9", "04", "040")
98
+ end
99
+
100
+ should "return correct message" do
101
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
102
+ end
103
+
104
+ should "return leading numbers" do
105
+ refute_empty @nibbler.rejected
106
+ assert_equal "3", @nibbler.rejected[0]
107
+ assert_equal "0", @nibbler.rejected[1]
108
+ end
109
+
110
+ end
111
+
112
+ context "2 leading numbers" do
113
+
114
+ setup do
115
+ @message = @nibbler.parse(0x60, 0x30, "9", "04", "040")
116
+ end
117
+
118
+ should "return correct message" do
119
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
120
+ end
121
+
122
+ should "return leading numbers" do
123
+ refute_empty @nibbler.rejected
124
+ assert_equal "6", @nibbler.rejected[0]
125
+ assert_equal "0", @nibbler.rejected[1]
126
+ assert_equal "3", @nibbler.rejected[2]
127
+ assert_equal "0", @nibbler.rejected[3]
128
+ end
129
+
130
+ end
131
+
132
+ context "3 leading numbers" do
133
+
134
+ setup do
135
+ @message = @nibbler.parse(0x00, 0x30, "9", "04", "040")
136
+ end
137
+
138
+ should "return correct message" do
139
+ assert_equal(::MIDIMessage::NoteOn, @message.class)
140
+ end
141
+
142
+ should "return leading numbers" do
143
+ refute_empty @nibbler.rejected
144
+ assert_equal "0", @nibbler.rejected[0]
145
+ assert_equal "0", @nibbler.rejected[1]
146
+ assert_equal "3", @nibbler.rejected[2]
147
+ assert_equal "0", @nibbler.rejected[3]
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+
154
+ end