jsound 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +3 -0
- data/LICENSE.txt +27 -0
- data/README.md +96 -0
- data/Rakefile +19 -0
- data/examples/harmonizer.rb +25 -0
- data/examples/launchpad/launchpad.rb +65 -0
- data/examples/launchpad/launchpad_generator.rb +111 -0
- data/examples/list_devices.rb +6 -0
- data/examples/monitor.rb +15 -0
- data/examples/notes.rb +90 -0
- data/examples/transposer.rb +20 -0
- data/lib/jsound.rb +4 -0
- data/lib/jsound/convert.rb +30 -0
- data/lib/jsound/midi.rb +77 -0
- data/lib/jsound/midi/device.rb +72 -0
- data/lib/jsound/midi/device_list.rb +157 -0
- data/lib/jsound/midi/devices/generator.rb +22 -0
- data/lib/jsound/midi/devices/input_device.rb +51 -0
- data/lib/jsound/midi/devices/jdevice.rb +100 -0
- data/lib/jsound/midi/devices/monitor.rb +18 -0
- data/lib/jsound/midi/devices/output_device.rb +36 -0
- data/lib/jsound/midi/devices/recorder.rb +56 -0
- data/lib/jsound/midi/devices/repeater.rb +28 -0
- data/lib/jsound/midi/devices/transformer.rb +30 -0
- data/lib/jsound/midi/message.rb +165 -0
- data/lib/jsound/midi/message_builder.rb +52 -0
- data/lib/jsound/midi/messages/channel_pressure.rb +26 -0
- data/lib/jsound/midi/messages/control_change.rb +29 -0
- data/lib/jsound/midi/messages/note_off.rb +10 -0
- data/lib/jsound/midi/messages/note_on.rb +29 -0
- data/lib/jsound/midi/messages/pitch_bend.rb +43 -0
- data/lib/jsound/midi/messages/poly_pressure.rb +29 -0
- data/lib/jsound/midi/messages/program_change.rb +27 -0
- data/lib/jsound/type_from_class_name.rb +23 -0
- data/spec/jsound/convert_spec.rb +68 -0
- data/spec/jsound/midi/device_spec.rb +75 -0
- data/spec/jsound/midi/devices/generator_spec.rb +21 -0
- data/spec/jsound/midi/devices/output_device_spec.rb +22 -0
- data/spec/jsound/midi/devices/recorder_spec.rb +88 -0
- data/spec/jsound/midi/devices/repeater_device_spec.rb +19 -0
- data/spec/jsound/midi/devices/transformer_spec.rb +20 -0
- data/spec/jsound/midi/devlice_list_spec.rb +60 -0
- data/spec/jsound/midi/message_builder_spec.rb +22 -0
- data/spec/jsound/midi/message_spec.rb +30 -0
- data/spec/jsound/midi/messages/note_off_spec.rb +62 -0
- data/spec/jsound/midi/messages/note_on_spec.rb +109 -0
- data/spec/jsound/midi/messages/pitch_bend_spec.rb +88 -0
- data/spec/jsound/midi_spec.rb +33 -0
- data/spec/jsound/type_from_class_name_spec.rb +26 -0
- data/spec/spec_helper.rb +23 -0
- metadata +103 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'jsound'
|
4
|
+
include JSound::Midi
|
5
|
+
include Devices
|
6
|
+
|
7
|
+
transposer = Transformer.new do |message|
|
8
|
+
message.pitch += 24 if message.respond_to? :pitch # transpose up two octaves
|
9
|
+
message
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adjust the INPUTS and OUTPUTS as needed to use the devices you want:
|
13
|
+
INPUTS.open_first >> transposer >> OUTPUTS.open_first
|
14
|
+
# For example, to send my Akai keyboard through the harmonizer to the OS X IAC bus, I can do:
|
15
|
+
# INPUTS.Akai >> transposer >> OUTPUTS.IAC
|
16
|
+
|
17
|
+
# force the script to keep running (MIDI devices run in a background thread)
|
18
|
+
while(true)
|
19
|
+
sleep 5
|
20
|
+
end
|
data/lib/jsound.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module JSound
|
2
|
+
|
3
|
+
# Helper methods for converting MIDI data values
|
4
|
+
module Convert
|
5
|
+
|
6
|
+
# The maximum value for unsigned 14-bit integer
|
7
|
+
MAX_14BIT_VALUE = 16383 # == 127 + (127 << 7)
|
8
|
+
|
9
|
+
# Convert a single integer to a [least_significant, most_significant] pair of 7-bit ints
|
10
|
+
def to_7bit(value)
|
11
|
+
[value & 127, (value >> 7) & 127]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Convert a [least_significant, most_significant] pair of 7-bit ints to a single integer
|
15
|
+
def from_7bit(lsb, msb)
|
16
|
+
lsb + (msb << 7)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Scales a float from the range [-1.0, 1.0] to the integer range [0, 16383]
|
20
|
+
def normalized_float_to_14bit(float)
|
21
|
+
(MAX_14BIT_VALUE*(float+1)/2).round
|
22
|
+
end
|
23
|
+
|
24
|
+
# Make all methods be module functions (accessible by sending the method name to module directly)
|
25
|
+
instance_methods.each do |method|
|
26
|
+
module_function method
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/jsound/midi.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'jsound/midi/message'
|
2
|
+
require 'jsound/midi/messages/channel_pressure'
|
3
|
+
require 'jsound/midi/messages/control_change'
|
4
|
+
require 'jsound/midi/messages/note_on'
|
5
|
+
require 'jsound/midi/messages/note_off'
|
6
|
+
require 'jsound/midi/messages/pitch_bend'
|
7
|
+
require 'jsound/midi/messages/poly_pressure'
|
8
|
+
require 'jsound/midi/messages/program_change'
|
9
|
+
|
10
|
+
require 'jsound/midi/message_builder'
|
11
|
+
|
12
|
+
require 'jsound/midi/device'
|
13
|
+
require 'jsound/midi/devices/generator'
|
14
|
+
require 'jsound/midi/devices/jdevice'
|
15
|
+
require 'jsound/midi/devices/input_device'
|
16
|
+
require 'jsound/midi/devices/output_device'
|
17
|
+
require 'jsound/midi/devices/monitor'
|
18
|
+
require 'jsound/midi/devices/recorder'
|
19
|
+
require 'jsound/midi/devices/repeater'
|
20
|
+
require 'jsound/midi/devices/transformer'
|
21
|
+
|
22
|
+
require 'jsound/midi/device_list'
|
23
|
+
|
24
|
+
|
25
|
+
module JSound
|
26
|
+
|
27
|
+
# Module containing all MIDI functionality.
|
28
|
+
#
|
29
|
+
# Also provies the core interface for accessing MIDI devices, see the device list constants defined here.
|
30
|
+
#
|
31
|
+
module Midi
|
32
|
+
include_package 'javax.sound.midi'
|
33
|
+
|
34
|
+
# All MIDI devices
|
35
|
+
# @return [DeviceList]
|
36
|
+
DEVICES = DeviceList.new
|
37
|
+
|
38
|
+
# MIDI input devices
|
39
|
+
# @return [DeviceList] a list of {Devices::InputDevice}s
|
40
|
+
INPUTS = DeviceList.new
|
41
|
+
|
42
|
+
# MIDI output devices
|
43
|
+
# @return [DeviceList] a list of {Devices::OutputDevice}s
|
44
|
+
OUTPUTS = DeviceList.new
|
45
|
+
|
46
|
+
# MIDI synthesizer devices
|
47
|
+
# @return [DeviceList]
|
48
|
+
SYNTHESIZERS = SYNTHS = DeviceList.new
|
49
|
+
|
50
|
+
# MIDI sequencer devices
|
51
|
+
# @return [DeviceList]
|
52
|
+
SEQUENCERS = DeviceList.new
|
53
|
+
|
54
|
+
# Refresh the list of connected devices.
|
55
|
+
# @note this happens automatically when JSound is required.
|
56
|
+
def refresh_devices
|
57
|
+
[DEVICES,INPUTS,OUTPUTS,SYNTHESIZERS,SEQUENCERS].each{|collection| collection.clear}
|
58
|
+
MidiSystem.getMidiDeviceInfo.each do |device_info|
|
59
|
+
java_device = MidiSystem.getMidiDevice(device_info)
|
60
|
+
device = Devices::JDevice.from_java(java_device)
|
61
|
+
case device.type
|
62
|
+
when :sequencer then SEQUENCERS << device
|
63
|
+
when :synthesizer then SYNTHESIZERS << device
|
64
|
+
when :input then INPUTS << device
|
65
|
+
when :output then OUTPUTS << device
|
66
|
+
end
|
67
|
+
DEVICES << device
|
68
|
+
end
|
69
|
+
DEVICES
|
70
|
+
end
|
71
|
+
module_function :refresh_devices
|
72
|
+
|
73
|
+
# Refresh devices automatically when loaded:
|
74
|
+
refresh_devices()
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module JSound
|
2
|
+
module Midi
|
3
|
+
|
4
|
+
# A device that can transmit and/or receive messages (typically MIDI messages).
|
5
|
+
# This default implementation simply passes through all messages.
|
6
|
+
class Device
|
7
|
+
include JSound::Mixins::TypeFromClassName
|
8
|
+
|
9
|
+
# Open the device and allocate the needed resources so that it can send and receive messages
|
10
|
+
# @note this operation is typically only relevant for Java-based devices such as {Devices::InputDevice} and {Devices::OutputDevice}
|
11
|
+
# @see DeviceList#open
|
12
|
+
def open
|
13
|
+
end
|
14
|
+
|
15
|
+
# return true if this device is currently open
|
16
|
+
def open?
|
17
|
+
# typically, ruby devices are always open, subclasses might not be
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
# Close the device and free up any resources used by this device.
|
22
|
+
# @note this operation is typically only relevant for Java-based devices such as {Devices::InputDevice} and {Devices::OutputDevice}
|
23
|
+
def close
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
# The base Device behaves like a 'pass through'
|
28
|
+
@type ||= (self.class == Device ? :pass_through : self.class.type)
|
29
|
+
end
|
30
|
+
|
31
|
+
# the device connected to this device's output
|
32
|
+
# @return [Device] the connected device, or nil if nothing is connected
|
33
|
+
def output
|
34
|
+
@output
|
35
|
+
end
|
36
|
+
|
37
|
+
# connect a device as the output for this device
|
38
|
+
# @param [Device] the device to connect, or nil to disconnect the currently connected device
|
39
|
+
# @see {#>>}
|
40
|
+
def output= device
|
41
|
+
@output = device
|
42
|
+
end
|
43
|
+
|
44
|
+
# Connect a device as the output for this device. shortcut for {#output=}
|
45
|
+
# @param [Device] the device to connect, or nil to disconnect the currently connected device
|
46
|
+
# @see {#output=}
|
47
|
+
def >> device
|
48
|
+
self.output= device
|
49
|
+
end
|
50
|
+
|
51
|
+
# Send a message to this device
|
52
|
+
# @param [Message]
|
53
|
+
# @see #<=
|
54
|
+
def message(message)
|
55
|
+
# default behavior is to pass the message to any connected output
|
56
|
+
@output.message(message) if @output
|
57
|
+
end
|
58
|
+
|
59
|
+
# send a message to this device. shortcut for {#message}
|
60
|
+
# @see #message
|
61
|
+
def <=(message)
|
62
|
+
message(message)
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"MIDI #{type} device"
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module JSound
|
2
|
+
module Midi
|
3
|
+
|
4
|
+
# A collection of MIDI {Device}s that provides various methods to lookup (and optionally auto-open) specific devices
|
5
|
+
#
|
6
|
+
# @see Midi the Midi module for constants to access your system devices
|
7
|
+
#
|
8
|
+
class DeviceList
|
9
|
+
|
10
|
+
# The devices within this collection.
|
11
|
+
attr_reader :devices
|
12
|
+
|
13
|
+
def initialize(list=[])
|
14
|
+
@devices = list
|
15
|
+
end
|
16
|
+
|
17
|
+
# Find the first {Device} matching the criteria
|
18
|
+
#
|
19
|
+
# @param criteria matches description against for a Regexp argument, matches the device field against the value for a Hash argument, otherwise checks for an equal description
|
20
|
+
# @return [Device] the first matching {Device} or nil if nothing matched
|
21
|
+
# @note I/O devices need to be opened before they can be used (see {Device#open})
|
22
|
+
# @see #find_all
|
23
|
+
# @see #open
|
24
|
+
# @example {OUTPUTS}.find "IAC Driver Bus 1" #=> find the first output with the exact description "IAC Driver Bus 1"
|
25
|
+
# @example {OUTPUTS}.find /IAC/ #=> find the first output with a description containing "IAC"
|
26
|
+
# @example {OUTPUTS}.find :vendor => "Apple Inc." #=> find the first output with the exact vendor field "Apple Inc."
|
27
|
+
# @example {OUTPUTS}.find :vendor => /Apple / #=> find the first output with a vendor field containing "Apple"
|
28
|
+
#
|
29
|
+
def find(criteria)
|
30
|
+
search :find, criteria
|
31
|
+
end
|
32
|
+
|
33
|
+
# Find all {Device}s matching the criteria
|
34
|
+
#
|
35
|
+
# @param criteria matches description against for a Regexp argument, matches the device field against the value for a Hash argument, otherwise checks for an equal description
|
36
|
+
# @return [Array] an Array of all matching {Device}s or [] if nothing matched
|
37
|
+
# @note I/O devices need to be opened before they can be used (see {Device#open})
|
38
|
+
# @see #find for examples
|
39
|
+
# @see #open
|
40
|
+
#
|
41
|
+
def find_all(criteria)
|
42
|
+
search :find_all, criteria
|
43
|
+
end
|
44
|
+
|
45
|
+
# Acts like Array#[] for Numeric and Range arguments. Otherwise acts like {#find_all}.
|
46
|
+
#
|
47
|
+
# @see #find_all
|
48
|
+
#
|
49
|
+
def [](criteria)
|
50
|
+
if criteria.kind_of? Fixnum or criteria.kind_of? Range
|
51
|
+
@devices[criteria]
|
52
|
+
else
|
53
|
+
find_all(criteria)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Find the first device matching the argument and open it.
|
58
|
+
#
|
59
|
+
# @param device matches description against for a Regexp argument, matches the device field against the value for a Hash argument, otherwise checks for an equal description
|
60
|
+
# @return [Device] the device
|
61
|
+
# @raise an error if no device can be found
|
62
|
+
# @see #find
|
63
|
+
# @see #find_all
|
64
|
+
#
|
65
|
+
def open(device)
|
66
|
+
device = find device unless device.is_a? Device
|
67
|
+
if device
|
68
|
+
device.open
|
69
|
+
else
|
70
|
+
raise "Device note found: #{device}"
|
71
|
+
end
|
72
|
+
device
|
73
|
+
end
|
74
|
+
|
75
|
+
# Find and open the first device with a description matching the argument.
|
76
|
+
#
|
77
|
+
# @return [Device] the device
|
78
|
+
# @raise an error if no device can be found
|
79
|
+
# @see #open
|
80
|
+
#
|
81
|
+
def /(regexp)
|
82
|
+
regexp = Regexp.new(regexp.to_s, Regexp::IGNORECASE) if not regexp.kind_of? Regexp
|
83
|
+
open regexp
|
84
|
+
end
|
85
|
+
|
86
|
+
# open the first device in this list
|
87
|
+
#
|
88
|
+
# @return [Device] the device
|
89
|
+
# @raise an error if no device can be found
|
90
|
+
# @see #open
|
91
|
+
#
|
92
|
+
def open_first
|
93
|
+
open @devices.first
|
94
|
+
end
|
95
|
+
|
96
|
+
# open and return the last device in this list
|
97
|
+
#
|
98
|
+
# @return [Device] the device
|
99
|
+
# @raise an error if no device can be found
|
100
|
+
# @see #open
|
101
|
+
#
|
102
|
+
def open_last
|
103
|
+
open @devices.first
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s
|
107
|
+
@devices.join("\n")
|
108
|
+
end
|
109
|
+
|
110
|
+
########################
|
111
|
+
private
|
112
|
+
|
113
|
+
def search(iterator, criteria)
|
114
|
+
field, target_value = field_and_target_value_for(criteria)
|
115
|
+
matcher = matcher_for(target_value)
|
116
|
+
@devices.send(iterator) do |device|
|
117
|
+
device.send(field).send(matcher, target_value)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def field_and_target_value_for(criteria)
|
122
|
+
if criteria.is_a? Hash
|
123
|
+
first_key = criteria.keys.first
|
124
|
+
return first_key, criteria[first_key]
|
125
|
+
else
|
126
|
+
return :description, criteria
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def matcher_for(target_value)
|
131
|
+
case target_value
|
132
|
+
when Regexp then '=~'
|
133
|
+
else '=='
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Pass method calls through to the underlying Array.
|
138
|
+
# If Array doesn't understand the method, call {#open} with a case-insensitive regexp match
|
139
|
+
# against description, treating underscore as a wildcard.
|
140
|
+
#
|
141
|
+
# @example # {INPUTS}.Akai => open the first "Akai" input device connected to this computer
|
142
|
+
# @example # {INPUTS}.Akai_2 => open an input device matching /Akai.*2/i
|
143
|
+
#
|
144
|
+
def method_missing(sym, *args, &block)
|
145
|
+
if @devices.respond_to? sym
|
146
|
+
@devices.send(sym, *args, &block)
|
147
|
+
elsif args.length == 0 and block.nil?
|
148
|
+
self.open /#{sym.to_s.sub '_','.*'}/i
|
149
|
+
else
|
150
|
+
super
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module JSound
|
2
|
+
module Midi
|
3
|
+
module Devices
|
4
|
+
|
5
|
+
# A device which provides methods for generating MIDI command messages.
|
6
|
+
# See JSound::Midi::Messages::Builder for the available methods.
|
7
|
+
class Generator < Device
|
8
|
+
|
9
|
+
# For all the methods defined in the MessageBuilder module (note_on, pitch_bend, control_change, etc),
|
10
|
+
# define a corresponding device method that constructs the message and sends the connected device
|
11
|
+
MessageBuilder.private_instance_methods.each do |method|
|
12
|
+
define_method(method) do |*args|
|
13
|
+
message = MessageBuilder.send(method, *args)
|
14
|
+
self.message message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module JSound
|
2
|
+
module Midi
|
3
|
+
module Devices
|
4
|
+
|
5
|
+
# A device that receives messages from a system MIDI input port,
|
6
|
+
# and passes the messages to any connected device.
|
7
|
+
#
|
8
|
+
# Available inputs are contained in the {INPUTS} list in the {Midi} module.
|
9
|
+
#
|
10
|
+
class InputDevice < JDevice
|
11
|
+
|
12
|
+
# Wrap a javax.sound.midi.MidiDevice receiver to provide MIDI output.
|
13
|
+
#
|
14
|
+
# @note Typically you won't instantiate these directly. Instead, find an input via the {INPUTS} list in the {Midi} module.
|
15
|
+
#
|
16
|
+
def initialize(java_device)
|
17
|
+
super(java_device, :input)
|
18
|
+
@bridge = Bridge.new(self)
|
19
|
+
java_device.transmitter.receiver = @bridge
|
20
|
+
end
|
21
|
+
|
22
|
+
def output=(device)
|
23
|
+
super
|
24
|
+
@bridge.output= device
|
25
|
+
end
|
26
|
+
|
27
|
+
# A subcomponent of {InputDevice} that implements javax.sound.midi.Receiver
|
28
|
+
# by translating incoming Java MIDI Messages to Ruby Messages.
|
29
|
+
class Bridge < Device
|
30
|
+
include javax.sound.midi.Receiver
|
31
|
+
|
32
|
+
def initialize(source_device)
|
33
|
+
@source_device = source_device
|
34
|
+
end
|
35
|
+
|
36
|
+
# Receives incoming Java MIDI Messages, converts them to Ruby Messages,
|
37
|
+
# and sends them to any connected devices.
|
38
|
+
def send(java_message, timestamp=-1)
|
39
|
+
self.message Message.from_java(java_message, :source => @source_device)
|
40
|
+
rescue
|
41
|
+
STDERR.puts $! if $DEBUG # otherwise this can get swallowed
|
42
|
+
raise
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module JSound
|
2
|
+
module Midi
|
3
|
+
module Devices
|
4
|
+
|
5
|
+
# A Java-provided MIDI device (wraps javax.sound.midi.MidiDevice objects)
|
6
|
+
class JDevice < Device
|
7
|
+
|
8
|
+
# the javax.sound.midi.MidiDevice.Info object for this java device
|
9
|
+
attr_reader :info
|
10
|
+
|
11
|
+
# the description of this device
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :description
|
14
|
+
|
15
|
+
attr_reader :type
|
16
|
+
|
17
|
+
# All open JDevices
|
18
|
+
# @note All open devices will be automatically closed at_exit
|
19
|
+
def self.open_devices
|
20
|
+
@@open_devices ||= []
|
21
|
+
end
|
22
|
+
at_exit do
|
23
|
+
# Close all open devices so we don't hang the program at shutdown time
|
24
|
+
for device in JDevice.open_devices
|
25
|
+
device.close
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(java_device, type)
|
30
|
+
@java_device = java_device
|
31
|
+
@info = @java_device.deviceInfo
|
32
|
+
@description = @info.description
|
33
|
+
@type = type
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_java(java_device)
|
37
|
+
case java_device
|
38
|
+
when javax.sound.midi.Sequencer then type = :sequencer
|
39
|
+
when javax.sound.midi.Synthesizer then type = :synthesizer
|
40
|
+
else
|
41
|
+
# This assumes a single device cannot be both an input and an output:
|
42
|
+
if java_device.maxTransmitters != 0
|
43
|
+
return InputDevice.new(java_device)
|
44
|
+
elsif java_device.maxReceivers != 0
|
45
|
+
return OutputDevice.new(java_device)
|
46
|
+
else
|
47
|
+
type = :unknown
|
48
|
+
end
|
49
|
+
end
|
50
|
+
new java_device, type
|
51
|
+
end
|
52
|
+
|
53
|
+
# @see Device#open
|
54
|
+
# @note All open devices will be automatically closed at_exit
|
55
|
+
def open
|
56
|
+
unless @java_device.open?
|
57
|
+
puts "Opening #{to_s}"
|
58
|
+
@java_device.open
|
59
|
+
self.class.open_devices << self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @see Device#close
|
64
|
+
def close
|
65
|
+
if @java_device.open?
|
66
|
+
puts "Closing #{to_s}"
|
67
|
+
@java_device.close
|
68
|
+
self.class.open_devices.delete(self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def method_missing(sym, *args, &block)
|
73
|
+
if @java_device.respond_to? sym
|
74
|
+
@java_device.send(sym, *args, &block)
|
75
|
+
else
|
76
|
+
@info.send(sym, *args, &block)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def respond_to?(sym)
|
81
|
+
super or @java_device.respond_to? sym or info.respond_to? sym
|
82
|
+
end
|
83
|
+
|
84
|
+
def [](field)
|
85
|
+
send field
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
"#{super}: #{info.description}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def inspect
|
93
|
+
to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|