unimidi 0.3.5 → 0.4.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.
@@ -0,0 +1,113 @@
1
+ module UniMIDI
2
+
3
+ # A MIDI input device
4
+ class Input
5
+
6
+ extend Device::ClassMethods
7
+ include Device::InstanceMethods
8
+
9
+ # All MIDI input devices -- used to populate the class
10
+ # @return [Array<Input>]
11
+ def self.all
12
+ Loader.devices(:direction => :input)
13
+ end
14
+
15
+ # The device buffer
16
+ # @return [Array<Hash>]
17
+ def buffer
18
+ @device.buffer
19
+ end
20
+
21
+ #
22
+ # Plucks data from the input buffer and returns it as array of MIDI event hashes as such:
23
+ # [
24
+ # { :data => [144, 60, 100], :timestamp => 1024 },
25
+ # { :data => [128, 60, 100], :timestamp => 1100 },
26
+ # { :data => [144, 40, 120], :timestamp => 1200 }
27
+ # ]
28
+ #
29
+ # In this case, the data is an array of Numeric bytes
30
+ # The timestamp is the number of millis since this input was enabled
31
+ # Arguments are passed to the underlying device object
32
+ #
33
+ # @param [*Object] args
34
+ # @return [Array<Hash>]
35
+ def gets(*args)
36
+ @device.gets(*args)
37
+ rescue SystemExit, Interrupt
38
+ exit
39
+ end
40
+
41
+ #
42
+ # Plucks data from the input buffer and returns it as array of MIDI event hashes.
43
+ # Similar to Input#gets except that the returned message data as string of hex digits eg:
44
+ # [
45
+ # { :data => "904060", :timestamp => 904 },
46
+ # { :data => "804060", :timestamp => 1150 },
47
+ # { :data => "90447F", :timestamp => 1300 }
48
+ # ]
49
+ #
50
+ # @param [*Object] args
51
+ # @return [Array<Hash>]
52
+ def gets_s(*args)
53
+ @device.gets_s(*args)
54
+ rescue SystemExit, Interrupt
55
+ exit
56
+ end
57
+ alias_method :gets_bytestr, :gets_s
58
+ alias_method :gets_hex, :gets_s
59
+
60
+ #
61
+ # Plucks data from the input buffer and returns it as an array of data bytes such as
62
+ # [144, 60, 100, 128, 60, 100, 144, 40, 120]
63
+ #
64
+ # @param [*Object] args
65
+ # @return [Array<Fixnum>]
66
+ def gets_data(*args)
67
+ arr = gets(*args)
68
+ arr.map { |msg| msg[:data] }.inject(:+)
69
+ end
70
+
71
+ #
72
+ # Plucks data from the input buffer and returns it as a string of data such as
73
+ # "90406080406090447F"
74
+ #
75
+ # @param [*Object] args
76
+ # @return [String]
77
+ def gets_data_s(*args)
78
+ arr = gets_bytestr(*args)
79
+ arr.map { |msg| msg[:data] }.join
80
+ end
81
+ alias_method :gets_data_bytestr, :gets_data_s
82
+ alias_method :gets_data_hex, :gets_data_s
83
+
84
+ # Clears the input buffer
85
+ # @return [Array]
86
+ def clear_buffer
87
+ @device.buffer.clear
88
+ end
89
+
90
+ # Gets any messages in the buffer in the same format as Input#gets, without removing them from the buffer
91
+ # @param [*Object] args
92
+ # @return [Array<Hash>]
93
+ def gets_buffer(*args)
94
+ @device.buffer
95
+ end
96
+
97
+ # Gets any messages in the buffer in the same format as Input#gets_s, without removing them from the buffer
98
+ # @param [*Object] args
99
+ # @return [Array<Hash>]
100
+ def gets_buffer_s(*args)
101
+ @device.buffer.map { |msg| msg[:data] = TypeConversion.numeric_byte_array_to_hex_string(msg[:data]); msg }
102
+ end
103
+
104
+ # Gets any messages in the buffer in the same format as Input#gets_data without removing them from the buffer
105
+ # @param [*Object] args
106
+ # @return [Array<Fixnum>]
107
+ def gets_buffer_data(*args)
108
+ @device.buffer.map { |msg| msg[:data] }
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,30 @@
1
+ module UniMIDI
2
+
3
+ # Populate UniMIDI devices using the underlying device objects from the platform-specific gems
4
+ module Loader
5
+
6
+ extend self
7
+
8
+ # Use the given platform-specific adapter to load devices
9
+ # @param [UniMIDI::Adapter::Loader] loader
10
+ def use(loader)
11
+ @loader = loader
12
+ end
13
+
14
+ # @param [Hash] options
15
+ # @option options [Symbol] :direction Return only a particular direction of device eg :input, :output
16
+ # @return [Array<Input>, Array<Output>]
17
+ def devices(options = {})
18
+ if @devices.nil?
19
+ inputs = @loader.inputs.map { |device| ::UniMIDI::Input.new(device) }
20
+ outputs = @loader.outputs.map { |device| ::UniMIDI::Output.new(device) }
21
+ @devices = {
22
+ :input => inputs,
23
+ :output => outputs
24
+ }
25
+ end
26
+ options[:direction].nil? ? @devices.values.flatten : @devices[options[:direction]]
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,63 @@
1
+ module UniMIDI
2
+
3
+ # A MIDI output device
4
+ class Output
5
+
6
+ extend Device::ClassMethods
7
+ include Device::InstanceMethods
8
+
9
+ # All MIDI output devices -- used to populate the class
10
+ # @return [Array<Output>]
11
+ def self.all
12
+ Loader.devices(:direction => :output)
13
+ end
14
+
15
+ # Sends a message to the output.
16
+ #
17
+ # The message format can be:
18
+ #
19
+ # 1. Numeric bytes eg output.puts(0x90, 0x40, 0x40)
20
+ # 2. An array of numeric bytes [0x90, 0x40, 0x40]
21
+ # 3. A string of bytes eg "904040"
22
+ # 4. An array of strings ["904040", "804040"]
23
+ #
24
+ # @param [*Array<Fixnum>, *Array<String>, *Fixnum, *String] messages
25
+ # @return [Array<Fixnum>, Array<String>]
26
+ def puts(*messages)
27
+ message = messages.first
28
+ case message
29
+ when Array then message.each { |message| puts(*message) }
30
+ when Fixnum then puts_bytes(*messages)
31
+ when String then puts_s(*messages)
32
+ else
33
+ if message.respond_to?(:to_bytes)
34
+ puts_bytes(*message.to_bytes.flatten)
35
+ elsif message.respond_to?(:to_a)
36
+ puts_bytes(*message.to_a.flatten)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Sends a message to the output in a form of a string eg "904040". This method does not do
42
+ # type checking
43
+ # @param [*String] messages
44
+ # @return [Array<String>, Array<Array<String>>]
45
+ def puts_s(*messages)
46
+ @device.puts_s(*messages)
47
+ messages.count < 2 ? messages[0] : messages
48
+ end
49
+ alias_method :puts_bytestr, :puts_s
50
+ alias_method :puts_hex, :puts_s
51
+
52
+ # Sends a message to the output in a form of bytes eg output.puts_bytes(0x90, 0x40, 0x40).
53
+ # This method does not do type checking.
54
+ # @param [*Array<Fixnum>] messages
55
+ # @return [Array<Fixnum>, Array<Array<Fixnum>>]
56
+ def puts_bytes(*messages)
57
+ @device.puts_bytes(*messages)
58
+ messages.count < 2 ? messages[0] : messages
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -1,12 +1,12 @@
1
1
  module UniMIDI
2
-
3
- class Platform
4
2
 
5
- include Singleton
3
+ # Deal with different dependencies between different user environments
4
+ module Platform
6
5
 
7
- attr_reader :interface
6
+ extend self
8
7
 
9
- def initialize
8
+ # Loads the proper MIDI library and adapter for the user's environment
9
+ def bootstrap
10
10
  lib = case RUBY_PLATFORM
11
11
  when /darwin/ then "ffi-coremidi"
12
12
  when /java/ then "midi-jruby"
@@ -14,12 +14,13 @@ module UniMIDI
14
14
  when /mingw/ then "midi-winmm"
15
15
  end
16
16
  require("unimidi/adapter/#{lib}")
17
- @interface = case RUBY_PLATFORM
18
- when /darwin/ then CoreMIDIAdapter
19
- when /java/ then MIDIJRubyAdapter
20
- when /linux/ then AlsaRawMIDIAdapter
21
- when /mingw/ then MIDIWinMMAdapter
17
+ interface = case RUBY_PLATFORM
18
+ when /darwin/ then Adapter::CoreMIDI
19
+ when /java/ then Adapter::MIDIJRuby
20
+ when /linux/ then Adapter::AlsaRawMIDI
21
+ when /mingw/ then Adapter::MIDIWinMM
22
22
  end
23
+ Loader.use(interface::Loader)
23
24
  end
24
25
 
25
26
  end
@@ -1,6 +1,6 @@
1
1
  module UniMIDI
2
2
 
3
- # Utility module for converting between different data formats
3
+ # Utility for converting between different data formats
4
4
  module TypeConversion
5
5
 
6
6
  extend self
@@ -0,0 +1,70 @@
1
+ require "helper"
2
+
3
+ class UniMIDI::AdapterTest < UniMIDI::TestCase
4
+
5
+ context "Adapter" do
6
+
7
+ setup do
8
+ TestDeviceHelper.setup
9
+ end
10
+
11
+ context "Device#type" do
12
+
13
+ should "be an input" do
14
+ input = TestDeviceHelper.devices[:input]
15
+ assert_equal(:input, input.type)
16
+ end
17
+
18
+ should "be an output" do
19
+ output = TestDeviceHelper.devices[:output]
20
+ assert_equal(:output, output.type)
21
+ end
22
+
23
+ end
24
+
25
+ context "Device.count" do
26
+
27
+ setup do
28
+ @inputs = Input.all
29
+ end
30
+
31
+ should "count all of the inputs" do
32
+ assert_equal @inputs.count, Input.count
33
+ end
34
+
35
+ end
36
+
37
+ context "Device.find_by_name" do
38
+
39
+ setup do
40
+ index = rand(0..(Output.count-1))
41
+ @output = Output.all[index]
42
+ end
43
+
44
+ should "select the correct input" do
45
+ result = Output.find_by_name(@output.name)
46
+ assert_equal @output, result
47
+ end
48
+
49
+ end
50
+
51
+ context "Device.first" do
52
+
53
+ setup do
54
+ @output = Output.all.first
55
+ end
56
+
57
+ should "open the output" do
58
+ @output.expects(:open)
59
+ output = Output.first
60
+ @output.unstub(:open)
61
+ end
62
+
63
+ should "return the correct output" do
64
+ output = Output.first
65
+ assert_equal @output, output
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,99 @@
1
+ require "helper"
2
+
3
+ class UniMIDI::ClassMethodsTest < UniMIDI::TestCase
4
+
5
+ context "ClassMethods" do
6
+
7
+ setup do
8
+ TestDeviceHelper.setup
9
+ end
10
+
11
+ context "#first" do
12
+
13
+ context "no block given" do
14
+ should "return first input" do
15
+ i = Input.first
16
+ assert_equal(Input.all.first, i)
17
+ end
18
+ end
19
+
20
+ context "block given" do
21
+ should "pass and return first input" do
22
+ sleep(1)
23
+ i = Input.first do |i|
24
+ assert_equal(true, i.enabled?)
25
+ end
26
+ assert_equal(Input.all.first, i)
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ context "#last" do
33
+
34
+ context "no block given" do
35
+ should "return last input" do
36
+ i = Input.last
37
+ assert_equal(Input.all.last, i)
38
+ end
39
+ end
40
+
41
+ context "block given" do
42
+ should "pass and return last input" do
43
+ sleep(1)
44
+ i = Input.last do |i|
45
+ assert_equal(true, i.enabled?)
46
+ end
47
+ assert_equal(Input.all.last, i)
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ context "#[]" do
54
+
55
+ should "return correct input" do
56
+ i = Input[0]
57
+ assert_equal(Input.first, i)
58
+ assert_equal(Input.all.first, i)
59
+ end
60
+
61
+ end
62
+
63
+ context "#use" do
64
+
65
+ context "block given" do
66
+ should "return and enable an input" do
67
+ sleep(1)
68
+ i = Input.use(0) do |i|
69
+ assert_equal(true, i.enabled?)
70
+ end
71
+ assert_equal(Input.first, i)
72
+ assert_equal(Input.all.first, i)
73
+ end
74
+
75
+ end
76
+
77
+ context "with symbol" do
78
+
79
+ should "return an enabled input" do
80
+ sleep(1)
81
+ input = Input.use(:first)
82
+ assert_equal(true, input.enabled?)
83
+ assert_equal(Input.first, input)
84
+ assert_equal(Input.all.first, input)
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ context "#all" do
92
+ should "return all devices" do
93
+ assert_equal(Loader.devices(:direction => :input), Input.all)
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,128 @@
1
+ require "helper"
2
+
3
+ class UniMIDI::FunctionalTest < UniMIDI::TestCase
4
+
5
+ # ** these tests assume that TestOutput is connected to TestInput
6
+ context "UniMIDI" do
7
+
8
+ setup do
9
+ sleep(1)
10
+ TestDeviceHelper.setup
11
+ end
12
+
13
+ context "full IO" do
14
+
15
+ context "using Arrays" do
16
+
17
+ setup do
18
+ @messages = VariousMIDIMessages
19
+ @messages_arr = @messages.inject { |a,b| a+b }.flatten
20
+ @received_arr = []
21
+ @pointer = 0
22
+ end
23
+
24
+ should "do IO" do
25
+ TestDeviceHelper.devices[:output].open do |output|
26
+ TestDeviceHelper.devices[:input].open do |input|
27
+
28
+ input.buffer.clear
29
+
30
+ @messages.each do |msg|
31
+
32
+ $>.puts "sending: " + msg.inspect
33
+
34
+ output.puts(msg)
35
+ sleep(1)
36
+ received = input.gets.map { |m| m[:data] }.flatten
37
+
38
+ $>.puts "received: " + received.inspect
39
+
40
+ assert_equal(@messages_arr.slice(@pointer, received.length), received)
41
+ @pointer += received.length
42
+ @received_arr += received
43
+ end
44
+ assert_equal(@messages_arr.length, @received_arr.length)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+
51
+ context "using byte Strings" do
52
+
53
+ setup do
54
+ @messages = VariousMIDIByteStrMessages
55
+ @messages_str = @messages.join
56
+ @received_str = ""
57
+ @pointer = 0
58
+ end
59
+
60
+ should "do IO" do
61
+ TestDeviceHelper.devices[:output].open do |output|
62
+ TestDeviceHelper.devices[:input].open do |input|
63
+
64
+ @messages.each do |msg|
65
+
66
+ $>.puts "sending: " + msg.inspect
67
+
68
+ output.puts(msg)
69
+ sleep(1)
70
+ received = input.gets_bytestr.map { |m| m[:data] }.flatten.join
71
+ $>.puts "received: " + received.inspect
72
+
73
+ assert_equal(@messages_str.slice(@pointer, received.length), received)
74
+ @pointer += received.length
75
+ @received_str += received
76
+ end
77
+ assert_equal(@messages_str, @received_str)
78
+
79
+ end
80
+ end
81
+
82
+
83
+ end
84
+
85
+ end
86
+
87
+ context "using MIDIMessages" do
88
+
89
+ setup do
90
+ @messages = VariousMIDIObjects
91
+ @messages_arr = @messages.map { |m| m.to_bytes }.flatten
92
+ @received_arr = []
93
+ @pointer = 0
94
+ end
95
+
96
+ should "do IO" do
97
+ TestDeviceHelper.devices[:output].open do |output|
98
+ TestDeviceHelper.devices[:input].open do |input|
99
+
100
+ #input.buffer.clear
101
+
102
+ @messages.each do |msg|
103
+
104
+ $>.puts "sending: " + msg.inspect
105
+
106
+ output.puts(msg)
107
+ sleep(1)
108
+ received = input.gets.map { |m| m[:data] }.flatten
109
+
110
+ $>.puts "received: " + received.inspect
111
+
112
+ assert_equal(@messages_arr.slice(@pointer, received.length), received)
113
+ @pointer += received.length
114
+ @received_arr += received
115
+ end
116
+ assert_equal(@messages_arr.length, @received_arr.length)
117
+
118
+ end
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ end