unimidi 0.3.5 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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