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.
@@ -1,18 +1,27 @@
1
1
  module MIDICommunications
2
-
3
- # Populate UniMIDI devices using the underlying device objects from the platform-specific gems
2
+ # Populates MIDI devices using platform-specific adapters.
3
+ #
4
+ # This class lazily loads and caches MIDI devices from the underlying
5
+ # platform adapter (macOS, Linux, Windows, or JRuby).
6
+ #
7
+ # @api private
4
8
  class Loader
5
9
  class << self
6
- # Use the given platform-specific adapter to load devices
7
- # @param [MIDICommunications::Adapter::Loader] loader
10
+ # Sets the platform-specific loader to use.
11
+ #
12
+ # @param loader [Module] a loader module with `inputs` and `outputs` methods
13
+ # @return [Module] the loader
8
14
  def use(loader)
9
15
  @loader = loader
10
16
  end
11
17
 
12
- # Get all MIDI devices
13
- # @param [Hash] options
14
- # @option options [Symbol] :direction Return only a particular direction of device eg :input, :output
15
- # @return [Array<Input>, Array<Output>]
18
+ # Returns all MIDI devices, optionally filtered by direction.
19
+ #
20
+ # Lazily loads and caches devices from the platform adapter on first call.
21
+ #
22
+ # @param options [Hash] filter options
23
+ # @option options [Symbol] :direction Return only :input or :output devices
24
+ # @return [Array<Input>, Array<Output>] array of devices
16
25
  def devices(options = {})
17
26
  if @devices.nil?
18
27
  inputs = @loader.inputs.map { |device| ::MIDICommunications::Input.new(device) }
@@ -1,27 +1,69 @@
1
1
  module MIDICommunications
2
-
3
- # A MIDI output device
2
+ # A MIDI output device for sending MIDI messages.
3
+ #
4
+ # Output devices send MIDI data to external instruments, software synthesizers,
5
+ # or other MIDI destinations. Use the class methods to discover and select
6
+ # available output devices.
7
+ #
8
+ # @example List available outputs
9
+ # MIDICommunications::Output.list
10
+ #
11
+ # @example Send a note to the first output
12
+ # output = MIDICommunications::Output.first
13
+ # output.puts(0x90, 60, 100) # Note On, middle C, velocity 100
14
+ # sleep(0.5)
15
+ # output.puts(0x80, 60, 0) # Note Off
16
+ #
17
+ # @example Send messages as hex strings
18
+ # output = MIDICommunications::Output.first
19
+ # output.puts_s("904060") # Note On
20
+ # output.puts_s("804060") # Note Off
21
+ #
22
+ # @example Interactive selection
23
+ # output = MIDICommunications::Output.gets
24
+ #
25
+ # @example Find by name
26
+ # output = MIDICommunications::Output.find_by_name("IAC Driver Bus 1")
27
+ # output.open
28
+ #
29
+ # @see Input For receiving MIDI messages
30
+ #
31
+ # @api public
4
32
  class Output
5
33
  extend Device::ClassMethods
6
34
  include Device::InstanceMethods
7
35
 
8
- # All MIDI output devices -- used to populate the class
9
- # @return [Array<Output>]
36
+ # Returns all available MIDI output devices.
37
+ #
38
+ # @return [Array<Output>] array of output devices
39
+ #
40
+ # @example
41
+ # outputs = MIDICommunications::Output.all
42
+ # outputs.each { |o| puts o.name }
10
43
  def self.all
11
44
  Loader.devices(direction: :output)
12
45
  end
13
46
 
14
- # Sends a message to the output.
47
+ # Sends a MIDI message to the output.
15
48
  #
16
- # The message format can be:
49
+ # Accepts multiple message formats for flexibility:
50
+ # - Numeric bytes: `output.puts(0x90, 0x40, 0x40)`
51
+ # - Array of numeric bytes: `output.puts([0x90, 0x40, 0x40])`
52
+ # - Hex string: `output.puts("904040")`
53
+ # - Array of strings: `output.puts(["904040", "804040"])`
54
+ # - Objects with `to_bytes` method: `output.puts(midi_event)`
17
55
  #
18
- # 1. Numeric bytes eg output.puts(0x90, 0x40, 0x40)
19
- # 2. An array of numeric bytes [0x90, 0x40, 0x40]
20
- # 3. A string of bytes eg "904040"
21
- # 4. An array of strings ["904040", "804040"]
56
+ # @param messages [Array<Integer>, Array<String>, Integer, String] MIDI messages in any supported format
57
+ # @return [Array<Integer>, Array<String>] the messages sent
22
58
  #
23
- # @param [*Array<Integer>, *Array<String>, *Integer, *String] messages
24
- # @return [Array<Integer>, Array<String>]
59
+ # @example Send Note On as bytes
60
+ # output.puts(0x90, 60, 100)
61
+ #
62
+ # @example Send Note On as array
63
+ # output.puts([0x90, 60, 100])
64
+ #
65
+ # @example Send Note On as hex string
66
+ # output.puts("903C64")
25
67
  def puts(*messages)
26
68
  message = messages.first
27
69
  case message
@@ -37,10 +79,17 @@ module MIDICommunications
37
79
  end
38
80
  end
39
81
 
40
- # Sends a message to the output in a form of a string eg "904040". This method does not do
41
- # type checking
42
- # @param [*String] messages
43
- # @return [Array<String>, Array<Array<String>>]
82
+ # Sends a MIDI message as a hex string.
83
+ #
84
+ # This is a lower-level method that does not perform type checking.
85
+ # Use {#puts} for automatic format detection.
86
+ #
87
+ # @param messages [String] one or more hex strings (e.g., "904040")
88
+ # @return [String, Array<String>] the message(s) sent
89
+ #
90
+ # @example
91
+ # output.puts_s("904060") # Note On
92
+ # output.puts_s("804060") # Note Off
44
93
  def puts_s(*messages)
45
94
  @device.puts_s(*messages)
46
95
  messages.count < 2 ? messages[0] : messages
@@ -48,10 +97,16 @@ module MIDICommunications
48
97
  alias puts_bytestr puts_s
49
98
  alias puts_hex puts_s
50
99
 
51
- # Sends a message to the output in a form of bytes eg output.puts_bytes(0x90, 0x40, 0x40).
52
- # This method does not do type checking.
53
- # @param [*Array<Integer>] messages
54
- # @return [Array<Integer>, Array<Array<Integer>>]
100
+ # Sends a MIDI message as numeric bytes.
101
+ #
102
+ # This is a lower-level method that does not perform type checking.
103
+ # Use {#puts} for automatic format detection.
104
+ #
105
+ # @param messages [Integer] numeric byte values (e.g., 0x90, 0x40, 0x40)
106
+ # @return [Integer, Array<Integer>] the message bytes sent
107
+ #
108
+ # @example
109
+ # output.puts_bytes(0x90, 0x40, 0x40) # Note On, note 64, velocity 64
55
110
  def puts_bytes(*messages)
56
111
  @device.puts_bytes(*messages)
57
112
  messages.count < 2 ? messages[0] : messages
@@ -1,10 +1,19 @@
1
1
  module MIDICommunications
2
-
3
- # Deal with different dependencies between different user environments
2
+ # Handles platform detection and adapter loading.
3
+ #
4
+ # Automatically detects the current platform (macOS, Linux, Windows, JRuby)
5
+ # and loads the appropriate low-level MIDI adapter.
6
+ #
7
+ # @api private
4
8
  module Platform
5
9
  extend self
6
10
 
7
- # Loads the proper MIDI library and adapter for the user's environment
11
+ # Loads the correct MIDI adapter for the current platform.
12
+ #
13
+ # Called automatically when the library is required. Detects the
14
+ # platform and loads the corresponding adapter gem.
15
+ #
16
+ # @return [void]
8
17
  def bootstrap
9
18
  require("midi-communications/adapter/#{platform_lib}")
10
19
  Loader.use(platform_module::Loader)
@@ -1,12 +1,18 @@
1
1
  module MIDICommunications
2
-
3
- # Utility for converting between different data formats
2
+ # Utility methods for converting between MIDI data formats.
3
+ #
4
+ # @api public
4
5
  module TypeConversion
5
6
  extend self
6
7
 
7
- # Convert an array of numeric bytes to string of hex bytes
8
- # @param [Array<Integer>] bytes An array of numeric bytes eg [0x90, 0x40, 0x40]
9
- # @return [String] A string of hex bytes eg "904040"
8
+ # Converts an array of numeric bytes to a hex string.
9
+ #
10
+ # @param bytes [Array<Integer>] array of numeric bytes (e.g., [0x90, 0x40, 0x40])
11
+ # @return [String] hex string representation (e.g., "904040")
12
+ #
13
+ # @example
14
+ # TypeConversion.numeric_byte_array_to_hex_string([0x90, 0x40, 0x40])
15
+ # # => "904040"
10
16
  def numeric_byte_array_to_hex_string(bytes)
11
17
  bytes.map { |b| b.to_s(16) }.join
12
18
  end
@@ -1,3 +1,4 @@
1
1
  module MIDICommunications
2
- VERSION = '0.6.1'.freeze
2
+ # Current version of the midi-communications gem.
3
+ VERSION = '0.7.0'.freeze
3
4
  end
@@ -18,6 +18,44 @@ require 'midi-communications/output'
18
18
 
19
19
  require_relative 'midi-communications/version'
20
20
 
21
+ # Platform-independent realtime MIDI input and output for Ruby.
22
+ #
23
+ # MIDICommunications provides a unified API for MIDI communication across
24
+ # different platforms (macOS, Linux, Windows, JRuby). It automatically
25
+ # detects the current platform and loads the appropriate low-level adapter.
26
+ #
27
+ # This library is part of the MusaDSL MIDI suite:
28
+ # - {https://github.com/javier-sy/midi-events MIDI Events} - MIDI message representation
29
+ # - {https://github.com/javier-sy/midi-parser MIDI Parser} - MIDI data parsing
30
+ # - {https://github.com/javier-sy/midi-communications MIDI Communications} - MIDI I/O (this library)
31
+ # - {https://github.com/javier-sy/midi-communications-macos MIDI Communications MacOS} - macOS adapter
32
+ #
33
+ # @example List all MIDI outputs
34
+ # MIDICommunications::Output.list
35
+ # # 0) IAC Driver Bus 1
36
+ # # 1) USB MIDI Device
37
+ #
38
+ # @example Send a note to the first output
39
+ # output = MIDICommunications::Output.first
40
+ # output.puts(0x90, 60, 100) # Note On, middle C, velocity 100
41
+ # sleep(0.5)
42
+ # output.puts(0x80, 60, 0) # Note Off
43
+ #
44
+ # @example Receive MIDI from an input
45
+ # input = MIDICommunications::Input.first
46
+ # loop do
47
+ # messages = input.gets
48
+ # messages.each { |m| puts m.inspect }
49
+ # end
50
+ #
51
+ # @example Interactive device selection
52
+ # output = MIDICommunications::Output.gets # Prompts user to select
53
+ # input = MIDICommunications::Input.gets
54
+ #
55
+ # @see Input MIDI input device class
56
+ # @see Output MIDI output device class
57
+ #
58
+ # @api public
21
59
  module MIDICommunications
22
60
  Platform.bootstrap
23
61
  end
@@ -9,20 +9,18 @@ Gem::Specification.new do |s|
9
9
  s.authors = ['Javier Sánchez Yeste']
10
10
  s.email = ['javier.sy@gmail.com']
11
11
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
12
- s.homepage = 'https://rubygems.org/gems/midi-communications'
12
+ s.homepage = 'https://github.com/javier-sy/midi-communications'
13
13
  s.license = 'LGPL-3.0-or-later'
14
14
 
15
15
  s.required_ruby_version = '>= 2.7'
16
16
 
17
- # TODO
18
- #s.metadata = {
19
- # "source_code_uri" => "https://",
20
- # "homepage_uri" => "",
21
- # "documentation_uri" => "",
22
- # "changelog_uri" => ""
23
- #}
17
+ s.metadata = {
18
+ 'homepage_uri' => s.homepage,
19
+ 'source_code_uri' => s.homepage,
20
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/midi-communications'
21
+ }
24
22
 
25
- s.add_runtime_dependency 'midi-communications-macos', '~> 0.6'
23
+ s.add_runtime_dependency 'midi-communications-macos', '~> 0.7'
26
24
  # s.add_runtime_dependency 'alsa-rawmidi', '~> 0.3', '>= 0.3.1'
27
25
  # s.add_runtime_dependency 'midi-jruby', '~> 0.1', '>= 0.1.4'
28
26
  # s.add_runtime_dependency 'midi-winmm', '~> 0.1', '>= 0.1.10'
@@ -30,4 +28,8 @@ Gem::Specification.new do |s|
30
28
  s.add_development_dependency 'minitest', '~>5', '>= 5.14.4'
31
29
  s.add_development_dependency 'rake', '~>13', '>= 13.0.6'
32
30
  s.add_development_dependency 'shoulda-context', '~>2', '>= 2.0.0'
31
+
32
+ s.add_development_dependency 'yard', '~> 0.9'
33
+ s.add_development_dependency 'redcarpet', '~> 3.6'
34
+ s.add_development_dependency 'webrick', '~> 1.8'
33
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: midi-communications
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Sánchez Yeste
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.6'
18
+ version: '0.7'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.6'
25
+ version: '0.7'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: minitest
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -83,6 +83,48 @@ dependencies:
83
83
  - - ">="
84
84
  - !ruby/object:Gem::Version
85
85
  version: 2.0.0
86
+ - !ruby/object:Gem::Dependency
87
+ name: yard
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '0.9'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '0.9'
100
+ - !ruby/object:Gem::Dependency
101
+ name: redcarpet
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '3.6'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '3.6'
114
+ - !ruby/object:Gem::Dependency
115
+ name: webrick
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '1.8'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '1.8'
86
128
  description: Access MIDI devices for MacOS, Linux (wip), Windows (wip) and JRuby (wip).
87
129
  email:
88
130
  - javier.sy@gmail.com
@@ -91,6 +133,8 @@ extensions: []
91
133
  extra_rdoc_files: []
92
134
  files:
93
135
  - ".gitignore"
136
+ - ".version"
137
+ - ".yardopts"
94
138
  - Gemfile
95
139
  - LICENSE
96
140
  - LICENSE.unimidi
@@ -114,10 +158,13 @@ files:
114
158
  - lib/midi-communications/type_conversion.rb
115
159
  - lib/midi-communications/version.rb
116
160
  - midi-communications.gemspec
117
- homepage: https://rubygems.org/gems/midi-communications
161
+ homepage: https://github.com/javier-sy/midi-communications
118
162
  licenses:
119
163
  - LGPL-3.0-or-later
120
- metadata: {}
164
+ metadata:
165
+ homepage_uri: https://github.com/javier-sy/midi-communications
166
+ source_code_uri: https://github.com/javier-sy/midi-communications
167
+ documentation_uri: https://www.rubydoc.info/gems/midi-communications
121
168
  rdoc_options: []
122
169
  require_paths:
123
170
  - lib