midi-communications 0.6.1 → 0.7.0

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.
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # MIDI Communications
2
2
 
3
+ [![Ruby Version](https://img.shields.io/badge/ruby-2.7+-red.svg)](https://www.ruby-lang.org/)
4
+ [![License](https://img.shields.io/badge/license-LGPL--3.0--or--later-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.html)
5
+
3
6
  **Platform independent realtime MIDI input and output for Ruby.**
4
7
 
5
8
  This library is part of a suite of Ruby libraries for MIDI:
@@ -50,7 +53,7 @@ Otherwise...
50
53
 
51
54
  Some examples are included with the library:
52
55
 
53
- * [Selecting a device](http://github.com/arirusso/javier-sy/midi-communications/blob/master/examples/select_a_device.rb)
56
+ * [Selecting a device](http://github.com/javier-sy/midi-communications/blob/master/examples/select_a_device.rb)
54
57
  * [MIDI input](http://github.com/javier-sy/midi-communications/blob/master/examples/input.rb)
55
58
  * [MIDI output](http://github.com/javier-sy/midi-communications/blob/master/examples/output.rb)
56
59
  * [MIDI Sysex output](http://github.com/javier-sy/midi-communications/blob/master/examples/sysex_output.rb)
@@ -67,18 +70,17 @@ See below for additional notes on testing with JRuby.
67
70
 
68
71
  ### Documentation
69
72
 
70
- [rdoc](http://rdoc.info/gems/midi-communications) (**TODO**)
73
+ [rdoc](http://rdoc.info/gems/midi-communications)
71
74
 
72
75
  ### Platform Specific Notes
73
76
 
74
77
  ##### JRuby
75
78
 
76
- * (**TO CONFIRM**) You must be in 1.9 mode. This is normally accomplished by passing --1.9 to JRuby at the command line. For testing in 1.9 mode, use `jruby --1.9 -S rake test`
77
- * (**TO CONFIRM**) javax.sound has some documented issues with SysEx messages in some versions OSX Snow Leopard which do affect this library.
79
+ * Not tested. Could have some problems.
78
80
 
79
81
  ##### Linux
80
82
 
81
- * (**TO CONFIRM**) *libasound* and *libasound-dev* packages are required
83
+ * Not tested. Could have some problems.
82
84
 
83
85
  ## Differences between [MIDI Communications](https://github.com/javier-sy/midi-communications) library and [UniMIDI](https://github.com/arirusso/unimidi) library
84
86
 
@@ -89,8 +91,6 @@ See below for additional notes on testing with JRuby.
89
91
  * Updated dependencies versions
90
92
  * Renamed module to MIDICommunications instead of UniMIDI
91
93
  * Renamed gem to midi-communications instead of unimidi
92
- * TODO: update tests to use rspec instead of rake
93
- * TODO: migrate to (or confirm it's working ok on) Ruby 3.0 and Ruby 3.1
94
94
 
95
95
  ## Then, why does exist this library if it is mostly a clone of another library?
96
96
 
@@ -124,16 +124,6 @@ I've decided to publish my own renamed versions of the modified dependencies bec
124
124
 
125
125
  All in all I have decided to publish a suite of libraries optimized for MusaDSL use case that also can be used by other people in their projects.
126
126
 
127
- | Function | Library | Based on Ari Russo's| Difference |
128
- | --- | --- | --- | --- |
129
- | MIDI Events representation | [MIDI Events](https://github.com/javier-sy/midi-events) | [MIDI Message](https://github.com/arirusso/midi-message) | removed parsing, small improvements |
130
- | MIDI Data parsing | [MIDI Parser](https://github.com/javier-sy/midi-parser) | [Nibbler](https://github.com/arirusso/nibbler) | removed process history information, minor optimizations |
131
- | MIDI communication with Instruments and Control Surfaces | [MIDI Communications](https://github.com/javier-sy/midi-communications) | [unimidi](https://github.com/arirusso/unimidi) | use of [MIDI Communications MacOS Layer](https://github.com/javier-sy/midi-communications-macos, removed process history information, removed buffering, removed command line script)
132
- | Low level MIDI interface to MacOS | [MIDI Communications MacOS Layer](https://github.com/javier-sy/midi-communications-macos) | [ffi-coremidi](https://github.com/arirusso/ffi-coremidi) | removed buffering and process history information, locking behaviour when waiting midi events, improved midi devices name detection, minor optimizations |
133
- | Low level MIDI interface to Linux | **TO DO** | | |
134
- | Low level MIDI interface to JRuby | **TO DO** | | |
135
- | Low level MIDI interface to Windows | **TO DO** | | |
136
-
137
127
  ## Author
138
128
 
139
129
  * [Javier Sánchez Yeste](https://github.com/javier-sy)
@@ -144,6 +134,6 @@ Thanks to [Ari Russo](http://github.com/arirusso) for his ruby library [unimidi]
144
134
 
145
135
  ### License
146
136
 
147
- [MIDI Communications](https://github.com/javier-sy/midi-communications) Copyright (c) 2021-2023 [Javier Sánchez Yeste](https://yeste.studio), licensed under LGPL 3.0 License
137
+ [MIDI Communications](https://github.com/javier-sy/midi-communications) Copyright (c) 2021-2025 [Javier Sánchez Yeste](https://yeste.studio), licensed under LGPL 3.0 License
148
138
 
149
139
  [unimidi](https://github.com/arirusso/unimidi) Copyright (c) 2010-2017 [Ari Russo](http://arirusso.com), licensed under Apache License 2.0 (see the file LICENSE.unimidi)
@@ -35,17 +35,16 @@ output = MIDICommunications::Output.use(0)
35
35
  output = MIDICommunications::Output.open(:first)
36
36
  output = MIDICommunications::Output.open(0)
37
37
 
38
- # If you want to wait to open the device, you can select it with any of these "finder" methods
39
-
38
+ # Note: first and last open the device automatically
40
39
  output = MIDICommunications::Output.first
40
+
41
+ # If you want to get a device without opening it, use at/[] or all
41
42
  output = MIDICommunications::Output[0]
43
+ output = MIDICommunications::Output.at(0)
42
44
  output = MIDICommunications::Output.all[0]
43
45
  output = MIDICommunications::Output.all.first
44
- output = MIDICommunications::Device.all_by_type(:output)[0]
45
- output = MIDICommunications::Device.all_by_type(:output).first
46
46
 
47
47
  # You'll need to call open on these before you use it or an exception will be raised
48
-
49
48
  output.open
50
49
 
51
50
  # It's also possible to select a device by name
@@ -54,4 +53,4 @@ output = MIDICommunications::Output.find_by_name('Roland UM-2 (1)').open
54
53
 
55
54
  # or using regex match
56
55
 
57
- output = MIDICommunications::Output.find { |device| device.name.match(/Launchpad/) }.open(:first)
56
+ output = MIDICommunications::Output.find { |device| device.name.match(/Launchpad/) }.open
@@ -2,17 +2,25 @@ require 'midi-jruby'
2
2
 
3
3
  module MIDICommunications
4
4
  module Adapter
5
- # Load underlying devices using the midi-jruby gem
5
+ # JRuby adapter using the midi-jruby gem.
6
+ #
7
+ # Uses Java MIDI API to communicate with MIDI devices on JRuby.
8
+ #
9
+ # @api private
6
10
  module JRuby
11
+ # Loader for JRuby MIDI devices.
12
+ # @api private
7
13
  module Loader
8
14
  extend self
9
15
 
10
- # @return [Array<JRuby::Input>]
16
+ # Returns all available MIDI input devices.
17
+ # @return [Array<MIDIJRuby::Input>]
11
18
  def inputs
12
19
  ::MIDIJRuby::Device.all_by_type[:input]
13
20
  end
14
21
 
15
- # @return [Array<JRuby::Output>]
22
+ # Returns all available MIDI output devices.
23
+ # @return [Array<MIDIJRuby::Output>]
16
24
  def outputs
17
25
  ::MIDIJRuby::Device.all_by_type[:output]
18
26
  end
@@ -2,17 +2,25 @@ require 'alsa-rawmidi'
2
2
 
3
3
  module MIDICommunications
4
4
  module Adapter
5
- # Load underlying devices using the alsa-rawmidi gem
5
+ # Linux adapter using the alsa-rawmidi gem.
6
+ #
7
+ # Uses ALSA to communicate with MIDI devices on Linux.
8
+ #
9
+ # @api private
6
10
  module Linux
11
+ # Loader for Linux MIDI devices.
12
+ # @api private
7
13
  module Loader
8
14
  extend self
9
15
 
10
- # @return [Array<Linux::Input>]
16
+ # Returns all available MIDI input devices.
17
+ # @return [Array<AlsaRawMIDI::Input>]
11
18
  def inputs
12
19
  ::AlsaRawMIDI::Device.all_by_type[:input]
13
20
  end
14
21
 
15
- # @return [Array<Linux::Output>]
22
+ # Returns all available MIDI output devices.
23
+ # @return [Array<AlsaRawMIDI::Output>]
16
24
  def outputs
17
25
  ::AlsaRawMIDI::Device.all_by_type[:output]
18
26
  end
@@ -1,18 +1,28 @@
1
1
  require 'midi-communications-macos'
2
2
 
3
3
  module MIDICommunications
4
+ # Platform-specific adapters for MIDI communication.
5
+ # @api private
4
6
  module Adapter
5
- # Load underlying devices using the coremidi gem
7
+ # macOS adapter using the midi-communications-macos gem.
8
+ #
9
+ # Uses Core MIDI to communicate with MIDI devices on macOS.
10
+ #
11
+ # @api private
6
12
  module MacOS
13
+ # Loader for macOS MIDI devices.
14
+ # @api private
7
15
  module Loader
8
16
  extend self
9
17
 
10
- # @return [Array<MacOS::Source>]
18
+ # Returns all available MIDI input sources.
19
+ # @return [Array<MIDICommunicationsMacOS::Source>]
11
20
  def inputs
12
21
  ::MIDICommunicationsMacOS::Endpoint.all_by_type[:source]
13
22
  end
14
23
 
15
- # @return [Array<MacOS::Destination>]
24
+ # Returns all available MIDI output destinations.
25
+ # @return [Array<MIDICommunicationsMacOS::Destination>]
16
26
  def outputs
17
27
  ::MIDICommunicationsMacOS::Endpoint.all_by_type[:destination]
18
28
  end
@@ -2,18 +2,25 @@ require 'midi-winmm'
2
2
 
3
3
  module MIDICommunications
4
4
  module Adapter
5
- # Load underlying devices using the midi-winmm gem
5
+ # Windows adapter using the midi-winmm gem.
6
+ #
7
+ # Uses Windows Multimedia API to communicate with MIDI devices.
8
+ #
9
+ # @api private
6
10
  module Windows
11
+ # Loader for Windows MIDI devices.
12
+ # @api private
7
13
  module Loader
8
-
9
14
  extend self
10
15
 
11
- # @return [Array<Windows::Input>]
16
+ # Returns all available MIDI input devices.
17
+ # @return [Array<MIDIWinMM::Input>]
12
18
  def inputs
13
19
  ::MIDIWinMM::Device.all_by_type[:input]
14
20
  end
15
21
 
16
- # @return [Array<Windows::Output>]
22
+ # Returns all available MIDI output devices.
23
+ # @return [Array<MIDIWinMM::Output>]
17
24
  def outputs
18
25
  ::MIDIWinMM::Device.all_by_type[:output]
19
26
  end
@@ -1,17 +1,40 @@
1
1
  module MIDICommunications
2
- # Common logic that is shared by both Input and Output devices
2
+ # Common logic shared by both {Input} and {Output} devices.
3
+ #
4
+ # This module provides the core device management functionality including
5
+ # device discovery, selection, and lifecycle management.
6
+ #
7
+ # @api private
3
8
  module Device
4
- # Methods that are shared by both Input and Output classes
9
+ # Class methods shared by both {Input} and {Output} classes.
10
+ #
11
+ # Provides device discovery and selection methods including enumeration,
12
+ # listing, searching by name, and interactive selection.
13
+ #
14
+ # @api public
5
15
  module ClassMethods
6
16
  include Enumerable
7
17
 
8
- # Iterate over all devices of this direction (eg Input, Output)
18
+ # Iterates over all devices of this type.
19
+ #
20
+ # @yield [device] each device
21
+ # @yieldparam device [Input, Output] a MIDI device
22
+ # @return [Enumerator] if no block given
23
+ #
24
+ # @example
25
+ # MIDICommunications::Output.each { |o| puts o.name }
9
26
  def each(&block)
10
27
  all.each(&block)
11
28
  end
12
29
 
13
- # Prints ids and names of each device to the console
14
- # @return [Array<String>]
30
+ # Prints the ID and name of each device to the console.
31
+ #
32
+ # @return [Array<String>] array of formatted device names
33
+ #
34
+ # @example
35
+ # MIDICommunications::Output.list
36
+ # # 0) IAC Driver Bus 1
37
+ # # 1) USB MIDI Device
15
38
  def list
16
39
  all.map do |device|
17
40
  name = "#{device.id}) #{device.display_name}"
@@ -20,15 +43,31 @@ module MIDICommunications
20
43
  end
21
44
  end
22
45
 
23
- # Shortcut to select a device by its name
24
- # @param [String, Symbol] name
25
- # @return [Input, Output]
46
+ # Finds a device by its name.
47
+ #
48
+ # @param name [String, Symbol] the device name to search for
49
+ # @return [Input, Output, nil] the matching device or nil if not found
50
+ #
51
+ # @example
52
+ # output = MIDICommunications::Output.find_by_name("IAC Driver Bus 1")
26
53
  def find_by_name(name)
27
54
  all.find { |device| name.to_s == device.name }
28
55
  end
29
56
 
30
- # Streamlined console prompt that asks the user to select a device
31
- # When their input is received, the device is selected and enabled
57
+ # Interactive console prompt for device selection.
58
+ #
59
+ # Displays available devices and waits for user input. When a valid
60
+ # selection is received, the device is opened and returned.
61
+ #
62
+ # @yield [device] optional block to execute with the opened device
63
+ # @yieldparam device [Input, Output] the selected device
64
+ # @return [Input, Output] the selected and opened device
65
+ #
66
+ # @example
67
+ # output = MIDICommunications::Output.gets
68
+ # # Select a MIDI output...
69
+ # # 0) IAC Driver Bus 1
70
+ # # > 0
32
71
  def gets(&block)
33
72
  device = nil
34
73
  direction = get_direction
@@ -47,21 +86,39 @@ module MIDICommunications
47
86
  device
48
87
  end
49
88
 
50
- # Select the first device and enable it
51
- # @return [Input, Output]
89
+ # Selects and opens the first available device.
90
+ #
91
+ # @yield [device] optional block to execute with the device
92
+ # @yieldparam device [Input, Output] the device
93
+ # @return [Input, Output] the first device, opened
94
+ #
95
+ # @example
96
+ # output = MIDICommunications::Output.first
52
97
  def first(&block)
53
98
  use_device(all.first, &block)
54
99
  end
55
100
 
56
- # Select the last device and enable it
57
- # @return [Input, Output]
101
+ # Selects and opens the last available device.
102
+ #
103
+ # @yield [device] optional block to execute with the device
104
+ # @yieldparam device [Input, Output] the device
105
+ # @return [Input, Output] the last device, opened
106
+ #
107
+ # @example
108
+ # output = MIDICommunications::Output.last
58
109
  def last(&block)
59
110
  use_device(all.last, &block)
60
111
  end
61
112
 
62
- # Select the device at the given index and enable it
63
- # @param [Integer] index
64
- # @return [Input, Output]
113
+ # Selects and opens the device at the given index.
114
+ #
115
+ # @param index [Integer, Symbol] device index or :first/:last
116
+ # @yield [device] optional block to execute with the device
117
+ # @yieldparam device [Input, Output] the device
118
+ # @return [Input, Output] the selected device, opened
119
+ #
120
+ # @example
121
+ # output = MIDICommunications::Output.use(0)
65
122
  def use(index, &block)
66
123
  index = case index
67
124
  when :first then 0
@@ -72,9 +129,14 @@ module MIDICommunications
72
129
  end
73
130
  alias open use
74
131
 
75
- # Select the device at the given index
76
- # @param [Integer] index
77
- # @return [Input, Output]
132
+ # Returns the device at the given index without opening it.
133
+ #
134
+ # @param index [Integer] device index
135
+ # @return [Input, Output] the device at the given index
136
+ #
137
+ # @example
138
+ # device = MIDICommunications::Output.at(0)
139
+ # device.open if device
78
140
  def at(index)
79
141
  all[index]
80
142
  end
@@ -101,9 +163,17 @@ module MIDICommunications
101
163
  end
102
164
  end
103
165
 
104
- # Methods that are shared by both Input and Output instances
166
+ # Instance methods shared by both {Input} and {Output} instances.
167
+ #
168
+ # Provides device lifecycle management (open, close) and access
169
+ # to device attributes (name, id, manufacturer, etc.).
170
+ #
171
+ # @api public
105
172
  module InstanceMethods
106
- # @param [AlsaRawMIDI::Input, AlsaRawMIDI::Output, MIDICommunicationsMacOS::Destination, MIDICommunicationsMacOS::Source, MIDIJRuby::Input, MIDIJRuby::Output, MIDIWinMM::Input, MIDIWinMM::Output] device
173
+ # Creates a new device wrapper.
174
+ #
175
+ # @param device [Object] platform-specific device object
176
+ # @api private
107
177
  def initialize(device)
108
178
  @device = device
109
179
  @enabled = false
@@ -111,11 +181,24 @@ module MIDICommunications
111
181
  populate_from_device
112
182
  end
113
183
 
114
- # Enable the device for use
115
- # Params are passed to the underlying device object
116
- # Can be passed a block to which the device will be passed in as the yieldparam
117
- # @param [*Object] args
184
+ # Opens the device for use.
185
+ #
186
+ # When a block is given, the device is automatically closed when
187
+ # the block exits. Otherwise, the device is closed at program exit.
188
+ #
189
+ # @param args [Object] arguments passed to the underlying device
190
+ # @yield [device] optional block to execute with the open device
191
+ # @yieldparam device [Input, Output] self
118
192
  # @return [Input, Output] self
193
+ #
194
+ # @example Open and close automatically with block
195
+ # output.open do |o|
196
+ # o.puts(0x90, 60, 100)
197
+ # end # device closed here
198
+ #
199
+ # @example Open manually (closed at program exit)
200
+ # output.open
201
+ # output.puts(0x90, 60, 100)
119
202
  def open(*args)
120
203
  unless @enabled
121
204
  @device.open(*args)
@@ -135,10 +218,13 @@ module MIDICommunications
135
218
  self
136
219
  end
137
220
 
138
- # Close the device
139
- # Params are passed to the underlying device object
140
- # @param [*Object] args
141
- # @return [Boolean]
221
+ # Closes the device.
222
+ #
223
+ # @param args [Object] arguments passed to the underlying device
224
+ # @return [Boolean] true if the device was closed, false if already closed
225
+ #
226
+ # @example
227
+ # output.close
142
228
  def close(*args)
143
229
  if @enabled
144
230
  @device.close(*args)
@@ -149,14 +235,41 @@ module MIDICommunications
149
235
  end
150
236
  end
151
237
 
152
- # Returns true if the device is not enabled
153
- # @return [Boolean]
238
+ # Returns true if the device is closed (not enabled).
239
+ #
240
+ # @return [Boolean] true if device is closed
154
241
  def closed?
155
242
  !@enabled
156
243
  end
157
244
 
158
- # Add attributes for the device instance
159
- # :direction, :id, :name
245
+ # @!attribute [r] direction
246
+ # @return [Symbol] the device direction (:input or :output)
247
+
248
+ # @!attribute [r] enabled
249
+ # @return [Boolean] whether the device is currently open
250
+
251
+ # @!attribute [r] id
252
+ # @return [Integer] the device ID
253
+
254
+ # @!attribute [r] manufacturer
255
+ # @return [String] the device manufacturer name
256
+
257
+ # @!attribute [r] model
258
+ # @return [String] the device model name
259
+
260
+ # @!attribute [r] name
261
+ # @return [String] the device name
262
+
263
+ # @!attribute [r] display_name
264
+ # @return [String] the device display name
265
+
266
+ # @!method enabled?
267
+ # @return [Boolean] alias for {#enabled}
268
+
269
+ # @!method type
270
+ # @return [Symbol] alias for {#direction}
271
+
272
+ # @api private
160
273
  def self.included(base)
161
274
  base.send(:attr_reader, :direction)
162
275
  base.send(:attr_reader, :enabled)
@@ -1,42 +1,48 @@
1
1
  module MIDICommunications
2
2
  class Input
3
+ # Methods for reading MIDI messages from an input device.
4
+ #
5
+ # Provides multiple methods for retrieving MIDI data in different formats:
6
+ # numeric bytes, hex strings, or raw data arrays.
7
+ #
8
+ # @api public
3
9
  module StreamReader
4
- # Returns any data in the input buffer that have been received since the last call to a
5
- # StreamReader method. If a StreamReader method has not yet been called, all data received
6
- # since the program was initialized will be returned
10
+ # Reads MIDI messages from the input buffer.
7
11
  #
8
- # The data is returned as array of MIDI event hashes as such:
9
- # [
10
- # { data: [144, 60, 100], timestamp: 1024 },
11
- # { data: [128, 60, 100], timestamp: 1100 },
12
- # { data: [144, 40, 120], timestamp: 1200 }
13
- # ]
12
+ # Returns all messages received since the last read. Each message
13
+ # includes the MIDI data and a timestamp.
14
14
  #
15
- # In this case, the data is an array of Numeric bytes
16
- # The timestamp is the number of millis since this input was enabled
17
- # Arguments are passed to the underlying device object
15
+ # @param args [Object] arguments passed to the underlying device
16
+ # @return [Array<Hash>] array of message hashes with :data and :timestamp keys
18
17
  #
19
- # @param [*Object] args
20
- # @return [Array<Hash>]
18
+ # @example
19
+ # messages = input.gets
20
+ # # => [{ data: [144, 60, 100], timestamp: 1024 },
21
+ # # { data: [128, 60, 100], timestamp: 1100 }]
22
+ #
23
+ # @example Process messages in a loop
24
+ # loop do
25
+ # messages = input.gets
26
+ # messages.each { |m| puts m[:data].inspect }
27
+ # sleep(0.01)
28
+ # end
21
29
  def gets(*args)
22
30
  @device.gets(*args)
23
31
  rescue SystemExit, Interrupt
24
32
  exit
25
33
  end
26
34
 
27
- # Returns any data in the input buffer that have been received since the last call to a
28
- # StreamReader method. If a StreamReader method has not yet been called, all data received
29
- # since the program was initialized will be returned
35
+ # Reads MIDI messages as hex strings.
36
+ #
37
+ # Similar to {#gets} but returns data as hex strings instead of byte arrays.
30
38
  #
31
- # Similar to Input#gets except that the returned message data as string of hex digits eg:
32
- # [
33
- # { data: "904060", timestamp: 904 },
34
- # { data: "804060", timestamp: 1150 },
35
- # { data: "90447F", timestamp: 1300 }
36
- # ]
39
+ # @param args [Object] arguments passed to the underlying device
40
+ # @return [Array<Hash>] array of message hashes with :data (String) and :timestamp keys
37
41
  #
38
- # @param [*Object] args
39
- # @return [Array<Hash>]
42
+ # @example
43
+ # messages = input.gets_s
44
+ # # => [{ data: "904060", timestamp: 904 },
45
+ # # { data: "804060", timestamp: 1150 }]
40
46
  def gets_s(*args)
41
47
  @device.gets_s(*args)
42
48
  rescue SystemExit, Interrupt
@@ -45,29 +51,33 @@ module MIDICommunications
45
51
  alias gets_bytestr gets_s
46
52
  alias gets_hex gets_s
47
53
 
48
- # Returns any data in the input buffer that have been received since the last call to a
49
- # StreamReader method. If a StreamReader method has not yet been called, all data received
50
- # since the program was initialized will be returned
54
+ # Reads MIDI data as a flat array of bytes.
51
55
  #
52
- # Similar to Input#gets except that the returned message data as an array of data bytes such as
53
- # [144, 60, 100, 128, 60, 100, 144, 40, 120]
56
+ # Returns all message data concatenated into a single array,
57
+ # without timestamps.
54
58
  #
55
- # @param [*Object] args
56
- # @return [Array<Integer>]
59
+ # @param args [Object] arguments passed to the underlying device
60
+ # @return [Array<Integer>] flat array of all MIDI bytes
61
+ #
62
+ # @example
63
+ # data = input.gets_data
64
+ # # => [144, 60, 100, 128, 60, 100, 144, 40, 120]
57
65
  def gets_data(*args)
58
66
  arr = gets(*args)
59
67
  arr.map { |msg| msg[:data] }.inject(:+)
60
68
  end
61
69
 
62
- # Returns any data in the input buffer that have been received since the last call to a
63
- # StreamReader method. If a StreamReader method has not yet been called, all data received
64
- # since the program was initialized will be returned
70
+ # Reads MIDI data as a concatenated hex string.
71
+ #
72
+ # Returns all message data concatenated into a single hex string,
73
+ # without timestamps.
65
74
  #
66
- # Similar to Input#gets except that the returned message data as a string of data such as
67
- # "90406080406090447F"
75
+ # @param args [Object] arguments passed to the underlying device
76
+ # @return [String] concatenated hex string of all MIDI data
68
77
  #
69
- # @param [*Object] args
70
- # @return [String]
78
+ # @example
79
+ # data = input.gets_data_s
80
+ # # => "90406080406090447F"
71
81
  def gets_data_s(*args)
72
82
  arr = gets_bytestr(*args)
73
83
  arr.map { |msg| msg[:data] }.join
@@ -1,14 +1,43 @@
1
1
  require 'midi-communications/input/stream_reader'
2
2
 
3
3
  module MIDICommunications
4
- # A MIDI input device
4
+ # A MIDI input device for receiving MIDI messages.
5
+ #
6
+ # Input devices receive MIDI data from external controllers, instruments,
7
+ # or other MIDI sources. Use the class methods to discover and select
8
+ # available input devices.
9
+ #
10
+ # @example List available inputs
11
+ # MIDICommunications::Input.list
12
+ #
13
+ # @example Open the first input and read messages
14
+ # input = MIDICommunications::Input.first
15
+ # messages = input.gets
16
+ # # => [{ data: [144, 60, 100], timestamp: 1024 }]
17
+ #
18
+ # @example Interactive selection
19
+ # input = MIDICommunications::Input.gets
20
+ #
21
+ # @example Find by name
22
+ # input = MIDICommunications::Input.find_by_name("USB MIDI Device")
23
+ # input.open
24
+ #
25
+ # @see Output For sending MIDI messages
26
+ # @see StreamReader For reading methods (gets, gets_s, etc.)
27
+ #
28
+ # @api public
5
29
  class Input
6
30
  extend Device::ClassMethods
7
31
  include Device::InstanceMethods
8
32
  include StreamReader
9
33
 
10
- # All MIDI input devices -- used to populate the class
11
- # @return [Array<Input>]
34
+ # Returns all available MIDI input devices.
35
+ #
36
+ # @return [Array<Input>] array of input devices
37
+ #
38
+ # @example
39
+ # inputs = MIDICommunications::Input.all
40
+ # inputs.each { |i| puts i.name }
12
41
  def self.all
13
42
  Loader.devices(direction: :input)
14
43
  end