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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +3 -3
- data/lib/unimidi.rb +16 -26
- data/lib/unimidi/adapter/alsa-rawmidi.rb +22 -17
- data/lib/unimidi/adapter/ffi-coremidi.rb +21 -25
- data/lib/unimidi/adapter/midi-jruby.rb +21 -16
- data/lib/unimidi/adapter/midi-winmm.rb +21 -16
- data/lib/unimidi/command.rb +26 -0
- data/lib/unimidi/device.rb +182 -0
- data/lib/unimidi/input.rb +113 -0
- data/lib/unimidi/loader.rb +30 -0
- data/lib/unimidi/output.rb +63 -0
- data/lib/unimidi/platform.rb +11 -10
- data/lib/unimidi/type_conversion.rb +1 -1
- data/test/adapter_test.rb +70 -0
- data/test/class_methods_test.rb +99 -0
- data/test/functional_test.rb +128 -0
- data/test/helper.rb +20 -25
- data/test/input_test.rb +46 -0
- data/test/platform_test.rb +41 -23
- data/test/type_conversion_test.rb +14 -6
- metadata +16 -11
- data/lib/unimidi/congruous_api_adapter.rb +0 -321
- data/test/congruous_api_adapter_test.rb +0 -36
- data/test/input_buffer_test.rb +0 -40
- data/test/io_test.rb +0 -115
- data/test/selectors_test.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a75ecec80f113f9831ddabe50fbb3a00e183faae
|
4
|
+
data.tar.gz: 174c3ec107b0d696f8780708c83a9abf8a1e33ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1b430c23cb93b0373834bab0c66a25286dc5ca6bcee99e963b3d40892781f7b076b00a13ada2828bc871d035706d63d2fa774e101a4c965df1b28ea05bcc5e3
|
7
|
+
data.tar.gz: cae4027fefcbb3b0a06cebbe1eefba944b7ca55419fc025cf752f1604915ce19845a70290aeae3cd941491c30b8dc5b53b4ffb7681235221356be95d0d7fa195
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -9,14 +9,14 @@ Also see [MicroMIDI](http://github.com/arirusso/micromidi) which builds a full M
|
|
9
9
|
* Supports Linux, JRuby, OSX, Windows and Cygwin
|
10
10
|
* No compilation required
|
11
11
|
* Both input and output to and from multiple devices concurrently
|
12
|
-
*
|
12
|
+
* Generalized handling of different MIDI and SysEx Message types
|
13
13
|
* (OSX Only) Use IAC to internally route MIDI to other programs
|
14
14
|
|
15
15
|
### Requirements
|
16
16
|
|
17
17
|
Using Ruby 1.9.2 or JRuby 1.6.1 (or newer) is strongly recommended. JRuby should be run in 1.9 mode where applicable
|
18
18
|
|
19
|
-
UniMIDI uses one of the following libraries, depending on which platform you're using it on. The necessary library should install automatically with the unimidi gem.
|
19
|
+
UniMIDI uses one of the following libraries, depending on which platform you're using it on. The necessary library should install automatically with the unimidi gem.
|
20
20
|
|
21
21
|
Platform
|
22
22
|
|
@@ -84,4 +84,4 @@ See below for additional notes on testing with JRuby
|
|
84
84
|
|
85
85
|
Apache 2.0, See the file LICENSE
|
86
86
|
|
87
|
-
Copyright (c) 2010-
|
87
|
+
Copyright (c) 2010-2014 Ari Russo
|
data/lib/unimidi.rb
CHANGED
@@ -1,34 +1,24 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
# libs
|
10
|
-
require "forwardable"
|
11
|
-
require "singleton"
|
1
|
+
#
|
2
|
+
# Realtime MIDI IO for Ruby
|
3
|
+
#
|
4
|
+
# (c)2010-2014 Ari Russo and licensed under the Apache 2.0 License
|
5
|
+
#
|
12
6
|
|
13
7
|
# modules
|
14
|
-
require "unimidi/
|
8
|
+
require "unimidi/command"
|
9
|
+
require "unimidi/device"
|
10
|
+
require "unimidi/loader"
|
11
|
+
require "unimidi/platform"
|
15
12
|
require "unimidi/type_conversion"
|
16
13
|
|
17
14
|
# classes
|
18
|
-
require "unimidi/
|
15
|
+
require "unimidi/input"
|
16
|
+
require "unimidi/output"
|
19
17
|
|
20
18
|
module UniMIDI
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
puts "input:"
|
27
|
-
Input.list
|
28
|
-
puts "output:"
|
29
|
-
Output.list
|
30
|
-
else
|
31
|
-
raise "Command #{command.to_s} not found"
|
32
|
-
end
|
33
|
-
end
|
19
|
+
|
20
|
+
VERSION = "0.4.4"
|
21
|
+
|
22
|
+
Platform.bootstrap
|
23
|
+
|
34
24
|
end
|
@@ -1,25 +1,30 @@
|
|
1
|
-
require
|
1
|
+
require "alsa-rawmidi"
|
2
2
|
|
3
3
|
module UniMIDI
|
4
4
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
# Load underlying devices using the alsa-rawmidi gem
|
8
|
+
module AlsaRawMIDI
|
9
|
+
|
10
|
+
module Loader
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# @return [Array<AlsaRawMIDI::Input>]
|
15
|
+
def inputs
|
16
|
+
::AlsaRawMIDI::Device.all_by_type[:input]
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<AlsaRawMIDI::Output>]
|
20
|
+
def outputs
|
21
|
+
::AlsaRawMIDI::Device.all_by_type[:output]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
11
25
|
|
12
|
-
class Output < CongruousApiOutput
|
13
|
-
defer_to AlsaRawMIDI::Output
|
14
|
-
device_class AlsaRawMIDI::Device
|
15
|
-
end
|
16
|
-
|
17
|
-
class Device < CongruousApiDevice
|
18
|
-
defer_to AlsaRawMIDI::Device
|
19
|
-
input_class Input
|
20
|
-
output_class Output
|
21
26
|
end
|
22
|
-
|
27
|
+
|
23
28
|
end
|
24
29
|
|
25
30
|
end
|
@@ -1,34 +1,30 @@
|
|
1
|
-
require
|
1
|
+
require "coremidi"
|
2
2
|
|
3
3
|
module UniMIDI
|
4
4
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
# Load underlying devices using the coremidi gem
|
8
|
+
module CoreMIDI
|
9
|
+
|
10
|
+
module Loader
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# @return [Array<CoreMIDI::Source>]
|
15
|
+
def inputs
|
16
|
+
::CoreMIDI::Endpoint.all_by_type[:source]
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<CoreMIDI::Destination>]
|
20
|
+
def outputs
|
21
|
+
::CoreMIDI::Endpoint.all_by_type[:destination]
|
22
|
+
end
|
11
23
|
|
12
|
-
class Output < CongruousApiOutput
|
13
|
-
defer_to CoreMIDI::Destination
|
14
|
-
device_class CoreMIDI::Endpoint
|
15
|
-
end
|
16
|
-
|
17
|
-
class Device < CongruousApiDevice
|
18
|
-
defer_to CoreMIDI::Endpoint
|
19
|
-
input_class Input
|
20
|
-
output_class Output
|
21
|
-
|
22
|
-
def self.populate
|
23
|
-
klass = @deference[self].respond_to?(:all_by_type) ? @deference[self] : @device_class
|
24
|
-
@devices = {
|
25
|
-
:input => klass.all_by_type[:source].map { |d| @input_class.new(d) },
|
26
|
-
:output => klass.all_by_type[:destination].map { |d| @output_class.new(d) }
|
27
|
-
}
|
28
24
|
end
|
29
|
-
|
25
|
+
|
30
26
|
end
|
31
|
-
|
27
|
+
|
32
28
|
end
|
33
29
|
|
34
30
|
end
|
@@ -1,23 +1,28 @@
|
|
1
|
-
require
|
1
|
+
require "midi-jruby"
|
2
2
|
|
3
3
|
module UniMIDI
|
4
4
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
# Load underlying devices using the midi-jruby gem
|
8
|
+
module MIDIJRuby
|
9
|
+
|
10
|
+
module Loader
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# @return [Array<MIDIJRuby::Input>]
|
15
|
+
def inputs
|
16
|
+
::MIDIJRuby::Device.all_by_type[:input]
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<MIDIJRuby::Output>]
|
20
|
+
def outputs
|
21
|
+
::MIDIJRuby::Device.all_by_type[:output]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
11
25
|
|
12
|
-
class Output < CongruousApiOutput
|
13
|
-
defer_to MIDIJRuby::Output
|
14
|
-
device_class MIDIJRuby::Device
|
15
|
-
end
|
16
|
-
|
17
|
-
class Device < CongruousApiDevice
|
18
|
-
defer_to MIDIJRuby::Device
|
19
|
-
input_class Input
|
20
|
-
output_class Output
|
21
26
|
end
|
22
27
|
|
23
28
|
end
|
@@ -1,23 +1,28 @@
|
|
1
|
-
require
|
1
|
+
require "midi-winmm"
|
2
2
|
|
3
3
|
module UniMIDI
|
4
4
|
|
5
|
-
module
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
# Load underlying devices using the midi-winmm gem
|
8
|
+
module MIDIWinMM
|
9
|
+
|
10
|
+
module Loader
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# @return [Array<MIDIWinMM::Input>]
|
15
|
+
def inputs
|
16
|
+
::MIDIWinMM::Device.all_by_type[:input]
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<MIDIWinMM::Output>]
|
20
|
+
def outputs
|
21
|
+
::MIDIWinMM::Device.all_by_type[:output]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
11
25
|
|
12
|
-
class Output < CongruousApiOutput
|
13
|
-
defer_to MIDIWinMM::Output
|
14
|
-
device_class MIDIWinMM::Device
|
15
|
-
end
|
16
|
-
|
17
|
-
class Device < CongruousApiDevice
|
18
|
-
defer_to MIDIWinMM::Device
|
19
|
-
input_class Input
|
20
|
-
output_class Output
|
21
26
|
end
|
22
27
|
|
23
28
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module UniMIDI
|
2
|
+
|
3
|
+
# Module for command-line use of UniMIDI. Used by the bin/unimidi script
|
4
|
+
module Command
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# Execute a command
|
9
|
+
# @param [Symbol] command
|
10
|
+
# @param [Hash] options
|
11
|
+
# @return [Boolean]
|
12
|
+
def exec(command, options = {})
|
13
|
+
if [:l, :list, :list_devices].include?(command)
|
14
|
+
puts "input:"
|
15
|
+
Input.list
|
16
|
+
puts "output:"
|
17
|
+
Output.list
|
18
|
+
true
|
19
|
+
else
|
20
|
+
raise "Command #{command.to_s} not found"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module UniMIDI
|
2
|
+
|
3
|
+
# Common logic that is shared by both Input and Output devices
|
4
|
+
module Device
|
5
|
+
|
6
|
+
# Methods that are shared by both Input and Output classes
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# Iterate over all devices of this direction (eg Input, Output)
|
12
|
+
def each(&block)
|
13
|
+
all.each { |device| yield(device) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Prints ids and names of each device to the console
|
17
|
+
# @return [Array<String>]
|
18
|
+
def list
|
19
|
+
all.map do |device|
|
20
|
+
name = device.pretty_name
|
21
|
+
puts(name)
|
22
|
+
name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Shortcut to select a device by its name
|
27
|
+
# @param [String, Symbol] name
|
28
|
+
# @return [Input, Output]
|
29
|
+
def find_by_name(name)
|
30
|
+
all.find { |device| name.to_s == device.name }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Streamlined console prompt that asks the user to select a device
|
34
|
+
# When their input is received, the device is selected and enabled
|
35
|
+
def gets(&block)
|
36
|
+
device = nil
|
37
|
+
class_name = self.name.split("::").last.downcase
|
38
|
+
puts ""
|
39
|
+
puts "Select a MIDI #{class_name}..."
|
40
|
+
while device.nil?
|
41
|
+
list
|
42
|
+
print "> "
|
43
|
+
selection = $stdin.gets.chomp
|
44
|
+
if selection != ""
|
45
|
+
selection = Integer(selection) rescue nil
|
46
|
+
device = all.find { |d| d.id == selection }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
device.open(&block) unless device.enabled?
|
50
|
+
device
|
51
|
+
end
|
52
|
+
|
53
|
+
# Select the first device and enable it
|
54
|
+
# @return [Input, Output]
|
55
|
+
def first(&block)
|
56
|
+
use_device(all.first, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Select the last device and enable it
|
60
|
+
# @return [Input, Output]
|
61
|
+
def last(&block)
|
62
|
+
use_device(all.last, &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Select the device at the given index and enable it
|
66
|
+
# @param [Fixnum] index
|
67
|
+
# @return [Input, Output]
|
68
|
+
def use(index, &block)
|
69
|
+
index = case index
|
70
|
+
when :first then 0
|
71
|
+
when :last then all.size - 1
|
72
|
+
else index
|
73
|
+
end
|
74
|
+
use_device(all[index], &block)
|
75
|
+
end
|
76
|
+
alias_method :open, :use
|
77
|
+
|
78
|
+
# Select the device at the given index
|
79
|
+
# @param [Fixnum] index
|
80
|
+
# @return [Input, Output]
|
81
|
+
def [](index)
|
82
|
+
all[index]
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Enable the given device
|
88
|
+
# @param [Input, Output] device
|
89
|
+
# @return [Input, Output]
|
90
|
+
def use_device(device, &block)
|
91
|
+
device.open(&block) unless device.enabled?
|
92
|
+
device
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
# Methods that are shared by both Input and Output instances
|
98
|
+
module InstanceMethods
|
99
|
+
|
100
|
+
# @param [AlsaRawMIDI::Input, AlsaRawMIDI::Output, CoreMIDI::Destination, CoreMIDI::Source, MIDIJRuby::Input, MIDIJRuby::Output, MIDIWinMM::Input, MIDIWinMM::Output] device
|
101
|
+
def initialize(device)
|
102
|
+
@device = device
|
103
|
+
@enabled = false
|
104
|
+
|
105
|
+
populate_from_device
|
106
|
+
end
|
107
|
+
|
108
|
+
# Is this device ready for io?
|
109
|
+
# @return [Boolean]
|
110
|
+
def enabled?
|
111
|
+
@enabled = true if @device.enabled # keep the adapter in sync
|
112
|
+
@enabled
|
113
|
+
end
|
114
|
+
|
115
|
+
# Enable the device for use
|
116
|
+
# Params are passed to the underlying device object
|
117
|
+
# Can be passed a block to which the device will be passed in as the yieldparam
|
118
|
+
# @param [*Object] args
|
119
|
+
# @return [Input, Output] self
|
120
|
+
def open(*args, &block)
|
121
|
+
@device.open(*args) unless enabled?
|
122
|
+
@enabled = true
|
123
|
+
if block_given?
|
124
|
+
begin
|
125
|
+
yield(self)
|
126
|
+
ensure
|
127
|
+
close
|
128
|
+
end
|
129
|
+
else
|
130
|
+
at_exit do
|
131
|
+
close
|
132
|
+
end
|
133
|
+
self
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# A human readable display name for this device
|
138
|
+
# @return [String]
|
139
|
+
def pretty_name
|
140
|
+
"#{id}) #{name}"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Close the device
|
144
|
+
# Params are passed to the underlying device object
|
145
|
+
# @param [*Object] args
|
146
|
+
# @return [Boolean]
|
147
|
+
def close(*args)
|
148
|
+
@device.close(*args)
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
# Add attributes for the device instance
|
153
|
+
# :direction, :id, :name
|
154
|
+
def self.included(base)
|
155
|
+
base.send(:attr_reader, :direction)
|
156
|
+
base.send(:attr_reader, :id)
|
157
|
+
base.send(:attr_reader, :name)
|
158
|
+
base.send(:alias_method, :type, :direction)
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Populate the direction attribute
|
164
|
+
def populate_direction
|
165
|
+
@direction = case @device.type
|
166
|
+
when :source, :input then :input
|
167
|
+
when :destination, :output then :output
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Populate attributes from the underlying device object
|
172
|
+
def populate_from_device
|
173
|
+
@id = @device.id
|
174
|
+
@name = @device.name
|
175
|
+
populate_direction
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|