midi-communications 0.6.0 → 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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.version +6 -0
- data/.yardopts +6 -0
- data/LICENSE +159 -668
- data/README.md +8 -18
- data/examples/select_a_device.rb +5 -6
- data/lib/midi-communications/adapter/jruby.rb +11 -3
- data/lib/midi-communications/adapter/linux.rb +11 -3
- data/lib/midi-communications/adapter/macos.rb +13 -3
- data/lib/midi-communications/adapter/windows.rb +11 -4
- data/lib/midi-communications/device.rb +147 -34
- data/lib/midi-communications/input/stream_reader.rb +49 -39
- data/lib/midi-communications/input.rb +32 -3
- data/lib/midi-communications/loader.rb +17 -8
- data/lib/midi-communications/output.rb +75 -20
- data/lib/midi-communications/platform.rb +12 -3
- data/lib/midi-communications/type_conversion.rb +11 -5
- data/lib/midi-communications/version.rb +4 -0
- data/lib/midi-communications.rb +40 -1
- data/midi-communications.gemspec +14 -10
- metadata +53 -5
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
module MIDICommunications
|
|
2
|
-
|
|
3
|
-
#
|
|
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
|
-
#
|
|
7
|
-
#
|
|
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
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
9
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
19
|
-
#
|
|
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
|
-
# @
|
|
24
|
-
#
|
|
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
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
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
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
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
|
-
#
|
|
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
|
|
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
|
-
#
|
|
2
|
+
# Utility methods for converting between MIDI data formats.
|
|
3
|
+
#
|
|
4
|
+
# @api public
|
|
4
5
|
module TypeConversion
|
|
5
6
|
extend self
|
|
6
7
|
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# @
|
|
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
|
data/lib/midi-communications.rb
CHANGED
|
@@ -16,7 +16,46 @@ require 'midi-communications/input'
|
|
|
16
16
|
require 'midi-communications/loader'
|
|
17
17
|
require 'midi-communications/output'
|
|
18
18
|
|
|
19
|
+
require_relative 'midi-communications/version'
|
|
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
|
|
19
59
|
module MIDICommunications
|
|
20
|
-
VERSION = '0.5.4'.freeze
|
|
21
60
|
Platform.bootstrap
|
|
22
61
|
end
|
data/midi-communications.gemspec
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
+
require_relative 'lib/midi-communications/version'
|
|
2
|
+
|
|
1
3
|
Gem::Specification.new do |s|
|
|
2
4
|
s.name = 'midi-communications'
|
|
3
|
-
s.version =
|
|
5
|
+
s.version = MIDICommunications::VERSION
|
|
4
6
|
s.date = '2025-08-23'
|
|
5
7
|
s.summary = 'Platform independent realtime MIDI input and output for Ruby'
|
|
6
8
|
s.description = 'Access MIDI devices for MacOS, Linux (wip), Windows (wip) and JRuby (wip).'
|
|
7
9
|
s.authors = ['Javier Sánchez Yeste']
|
|
8
10
|
s.email = ['javier.sy@gmail.com']
|
|
9
11
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
10
|
-
s.homepage = 'https://
|
|
12
|
+
s.homepage = 'https://github.com/javier-sy/midi-communications'
|
|
11
13
|
s.license = 'LGPL-3.0-or-later'
|
|
12
14
|
|
|
13
15
|
s.required_ruby_version = '>= 2.7'
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# "changelog_uri" => ""
|
|
21
|
-
#}
|
|
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
|
+
}
|
|
22
22
|
|
|
23
|
-
s.add_runtime_dependency 'midi-communications-macos', '~> 0.
|
|
23
|
+
s.add_runtime_dependency 'midi-communications-macos', '~> 0.7'
|
|
24
24
|
# s.add_runtime_dependency 'alsa-rawmidi', '~> 0.3', '>= 0.3.1'
|
|
25
25
|
# s.add_runtime_dependency 'midi-jruby', '~> 0.1', '>= 0.1.4'
|
|
26
26
|
# s.add_runtime_dependency 'midi-winmm', '~> 0.1', '>= 0.1.10'
|
|
@@ -28,4 +28,8 @@ Gem::Specification.new do |s|
|
|
|
28
28
|
s.add_development_dependency 'minitest', '~>5', '>= 5.14.4'
|
|
29
29
|
s.add_development_dependency 'rake', '~>13', '>= 13.0.6'
|
|
30
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'
|
|
31
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.
|
|
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.
|
|
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.
|
|
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
|
|
@@ -112,11 +156,15 @@ files:
|
|
|
112
156
|
- lib/midi-communications/output.rb
|
|
113
157
|
- lib/midi-communications/platform.rb
|
|
114
158
|
- lib/midi-communications/type_conversion.rb
|
|
159
|
+
- lib/midi-communications/version.rb
|
|
115
160
|
- midi-communications.gemspec
|
|
116
|
-
homepage: https://
|
|
161
|
+
homepage: https://github.com/javier-sy/midi-communications
|
|
117
162
|
licenses:
|
|
118
163
|
- LGPL-3.0-or-later
|
|
119
|
-
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
|
|
120
168
|
rdoc_options: []
|
|
121
169
|
require_paths:
|
|
122
170
|
- lib
|