midi-nibbler 0.2.3 → 0.2.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.
@@ -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