midi-communications 0.5.1
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 +7 -0
- data/.gitignore +10 -0
- data/Gemfile +3 -0
- data/LICENSE +674 -0
- data/LICENSE.unimidi +13 -0
- data/README.md +149 -0
- data/Rakefile +44 -0
- data/examples/input.rb +24 -0
- data/examples/output.rb +24 -0
- data/examples/select_a_device.rb +57 -0
- data/examples/sysex_output.rb +14 -0
- data/lib/midi-communications/adapter/jruby.rb +22 -0
- data/lib/midi-communications/adapter/linux.rb +22 -0
- data/lib/midi-communications/adapter/macos.rb +22 -0
- data/lib/midi-communications/adapter/windows.rb +23 -0
- data/lib/midi-communications/device.rb +195 -0
- data/lib/midi-communications/input/stream_reader.rb +79 -0
- data/lib/midi-communications/input.rb +16 -0
- data/lib/midi-communications/loader.rb +29 -0
- data/lib/midi-communications/output.rb +60 -0
- data/lib/midi-communications/platform.rb +33 -0
- data/lib/midi-communications/type_conversion.rb +14 -0
- data/lib/midi-communications.rb +22 -0
- data/midi-communications.gemspec +31 -0
- metadata +146 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
module MIDICommunications
|
2
|
+
class Input
|
3
|
+
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
|
7
|
+
#
|
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
|
+
# ]
|
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
|
18
|
+
#
|
19
|
+
# @param [*Object] args
|
20
|
+
# @return [Array<Hash>]
|
21
|
+
def gets(*args)
|
22
|
+
@device.gets(*args)
|
23
|
+
rescue SystemExit, Interrupt
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
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
|
30
|
+
#
|
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
|
+
# ]
|
37
|
+
#
|
38
|
+
# @param [*Object] args
|
39
|
+
# @return [Array<Hash>]
|
40
|
+
def gets_s(*args)
|
41
|
+
@device.gets_s(*args)
|
42
|
+
rescue SystemExit, Interrupt
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
alias gets_bytestr gets_s
|
46
|
+
alias gets_hex gets_s
|
47
|
+
|
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
|
51
|
+
#
|
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]
|
54
|
+
#
|
55
|
+
# @param [*Object] args
|
56
|
+
# @return [Array<Integer>]
|
57
|
+
def gets_data(*args)
|
58
|
+
arr = gets(*args)
|
59
|
+
arr.map { |msg| msg[:data] }.inject(:+)
|
60
|
+
end
|
61
|
+
|
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
|
65
|
+
#
|
66
|
+
# Similar to Input#gets except that the returned message data as a string of data such as
|
67
|
+
# "90406080406090447F"
|
68
|
+
#
|
69
|
+
# @param [*Object] args
|
70
|
+
# @return [String]
|
71
|
+
def gets_data_s(*args)
|
72
|
+
arr = gets_bytestr(*args)
|
73
|
+
arr.map { |msg| msg[:data] }.join
|
74
|
+
end
|
75
|
+
alias gets_data_bytestr gets_data_s
|
76
|
+
alias gets_data_hex gets_data_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'midi-communications/input/stream_reader'
|
2
|
+
|
3
|
+
module MIDICommunications
|
4
|
+
# A MIDI input device
|
5
|
+
class Input
|
6
|
+
extend Device::ClassMethods
|
7
|
+
include Device::InstanceMethods
|
8
|
+
include StreamReader
|
9
|
+
|
10
|
+
# All MIDI input devices -- used to populate the class
|
11
|
+
# @return [Array<Input>]
|
12
|
+
def self.all
|
13
|
+
Loader.devices(direction: :input)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MIDICommunications
|
2
|
+
|
3
|
+
# Populate UniMIDI devices using the underlying device objects from the platform-specific gems
|
4
|
+
class Loader
|
5
|
+
class << self
|
6
|
+
# Use the given platform-specific adapter to load devices
|
7
|
+
# @param [MIDICommunications::Adapter::Loader] loader
|
8
|
+
def use(loader)
|
9
|
+
@loader = loader
|
10
|
+
end
|
11
|
+
|
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>]
|
16
|
+
def devices(options = {})
|
17
|
+
if @devices.nil?
|
18
|
+
inputs = @loader.inputs.map { |device| ::MIDICommunications::Input.new(device) }
|
19
|
+
outputs = @loader.outputs.map { |device| ::MIDICommunications::Output.new(device) }
|
20
|
+
@devices = {
|
21
|
+
input: inputs,
|
22
|
+
output: outputs
|
23
|
+
}
|
24
|
+
end
|
25
|
+
options[:direction].nil? ? @devices.values.flatten : @devices[options[:direction]]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module MIDICommunications
|
2
|
+
|
3
|
+
# A MIDI output device
|
4
|
+
class Output
|
5
|
+
extend Device::ClassMethods
|
6
|
+
include Device::InstanceMethods
|
7
|
+
|
8
|
+
# All MIDI output devices -- used to populate the class
|
9
|
+
# @return [Array<Output>]
|
10
|
+
def self.all
|
11
|
+
Loader.devices(direction: :output)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sends a message to the output.
|
15
|
+
#
|
16
|
+
# The message format can be:
|
17
|
+
#
|
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"]
|
22
|
+
#
|
23
|
+
# @param [*Array<Integer>, *Array<String>, *Integer, *String] messages
|
24
|
+
# @return [Array<Integer>, Array<String>]
|
25
|
+
def puts(*messages)
|
26
|
+
message = messages.first
|
27
|
+
case message
|
28
|
+
when Array then messages.each { |array| puts(*array.flatten) }
|
29
|
+
when Integer then puts_bytes(*messages)
|
30
|
+
when String then puts_s(*messages)
|
31
|
+
else
|
32
|
+
if message.respond_to?(:to_bytes)
|
33
|
+
puts_bytes(*message.to_bytes.flatten)
|
34
|
+
elsif message.respond_to?(:to_a)
|
35
|
+
puts_bytes(*message.to_a.flatten)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
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>>]
|
44
|
+
def puts_s(*messages)
|
45
|
+
@device.puts_s(*messages)
|
46
|
+
messages.count < 2 ? messages[0] : messages
|
47
|
+
end
|
48
|
+
alias puts_bytestr puts_s
|
49
|
+
alias puts_hex puts_s
|
50
|
+
|
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>>]
|
55
|
+
def puts_bytes(*messages)
|
56
|
+
@device.puts_bytes(*messages)
|
57
|
+
messages.count < 2 ? messages[0] : messages
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module MIDICommunications
|
2
|
+
|
3
|
+
# Deal with different dependencies between different user environments
|
4
|
+
module Platform
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Loads the proper MIDI library and adapter for the user's environment
|
8
|
+
def bootstrap
|
9
|
+
require("midi-communications/adapter/#{platform_lib}")
|
10
|
+
Loader.use(platform_module::Loader)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def platform_lib
|
16
|
+
case RUBY_PLATFORM
|
17
|
+
when /darwin/ then 'macos'
|
18
|
+
when /java/ then 'jruby'
|
19
|
+
when /linux/ then 'linux'
|
20
|
+
when /mingw/ then 'windows'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def platform_module
|
25
|
+
case RUBY_PLATFORM
|
26
|
+
when /darwin/ then Adapter::MacOS
|
27
|
+
when /java/ then Adapter::JRuby
|
28
|
+
when /linux/ then Adapter::Linux
|
29
|
+
when /mingw/ then Adapter::Windows
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MIDICommunications
|
2
|
+
|
3
|
+
# Utility for converting between different data formats
|
4
|
+
module TypeConversion
|
5
|
+
extend self
|
6
|
+
|
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"
|
10
|
+
def numeric_byte_array_to_hex_string(bytes)
|
11
|
+
bytes.map { |b| b.to_s(16) }.join
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# MIDI Communications
|
3
|
+
# Platform independent realtime MIDI IO for Ruby
|
4
|
+
#
|
5
|
+
# (c)2021 Javier Sánchez Yeste for the modifications, licensed under LGPL 3.0 License
|
6
|
+
# (c)2011-2017 Ari Russo
|
7
|
+
#
|
8
|
+
|
9
|
+
# modules
|
10
|
+
require 'midi-communications/device'
|
11
|
+
require 'midi-communications/platform'
|
12
|
+
require 'midi-communications/type_conversion'
|
13
|
+
|
14
|
+
# classes
|
15
|
+
require 'midi-communications/input'
|
16
|
+
require 'midi-communications/loader'
|
17
|
+
require 'midi-communications/output'
|
18
|
+
|
19
|
+
module MIDICommunications
|
20
|
+
VERSION = '0.5.1'.freeze
|
21
|
+
Platform.bootstrap
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'midi-communications'
|
3
|
+
s.version = '0.5.1'
|
4
|
+
s.date = '2021-11-19'
|
5
|
+
s.summary = 'Platform independent realtime MIDI input and output for Ruby'
|
6
|
+
s.description = 'Access MIDI devices for MacOS, Linux (wip), Windows (wip) and JRuby (wip).'
|
7
|
+
s.authors = ['Javier Sánchez Yeste']
|
8
|
+
s.email = ['javier.sy@gmail.com']
|
9
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
10
|
+
s.homepage = 'https://rubygems.org/gems/midi-communications'
|
11
|
+
s.license = 'LGPL-3.0'
|
12
|
+
|
13
|
+
s.required_ruby_version = '~> 2.7'
|
14
|
+
|
15
|
+
# TODO
|
16
|
+
#s.metadata = {
|
17
|
+
# "source_code_uri" => "https://",
|
18
|
+
# "homepage_uri" => "",
|
19
|
+
# "documentation_uri" => "",
|
20
|
+
# "changelog_uri" => ""
|
21
|
+
#}
|
22
|
+
|
23
|
+
s.add_runtime_dependency 'midi-communications-macos', '~> 0.5', '>= 0.5.0'
|
24
|
+
# s.add_runtime_dependency 'alsa-rawmidi', '~> 0.3', '>= 0.3.1'
|
25
|
+
# s.add_runtime_dependency 'midi-jruby', '~> 0.1', '>= 0.1.4'
|
26
|
+
# s.add_runtime_dependency 'midi-winmm', '~> 0.1', '>= 0.1.10'
|
27
|
+
|
28
|
+
s.add_development_dependency 'minitest', '~> 5.14', '>= 5.14.4'
|
29
|
+
s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6'
|
30
|
+
s.add_development_dependency 'shoulda-context', '~> 2.0', '>= 2.0.0'
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: midi-communications
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Javier Sánchez Yeste
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: midi-communications-macos
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.5'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.5.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.5'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.5.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: minitest
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.14'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 5.14.4
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '5.14'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 5.14.4
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rake
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '13.0'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 13.0.6
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '13.0'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 13.0.6
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: shoulda-context
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '2.0'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.0'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.0.0
|
93
|
+
description: Access MIDI devices for MacOS, Linux (wip), Windows (wip) and JRuby (wip).
|
94
|
+
email:
|
95
|
+
- javier.sy@gmail.com
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- ".gitignore"
|
101
|
+
- Gemfile
|
102
|
+
- LICENSE
|
103
|
+
- LICENSE.unimidi
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- examples/input.rb
|
107
|
+
- examples/output.rb
|
108
|
+
- examples/select_a_device.rb
|
109
|
+
- examples/sysex_output.rb
|
110
|
+
- lib/midi-communications.rb
|
111
|
+
- lib/midi-communications/adapter/jruby.rb
|
112
|
+
- lib/midi-communications/adapter/linux.rb
|
113
|
+
- lib/midi-communications/adapter/macos.rb
|
114
|
+
- lib/midi-communications/adapter/windows.rb
|
115
|
+
- lib/midi-communications/device.rb
|
116
|
+
- lib/midi-communications/input.rb
|
117
|
+
- lib/midi-communications/input/stream_reader.rb
|
118
|
+
- lib/midi-communications/loader.rb
|
119
|
+
- lib/midi-communications/output.rb
|
120
|
+
- lib/midi-communications/platform.rb
|
121
|
+
- lib/midi-communications/type_conversion.rb
|
122
|
+
- midi-communications.gemspec
|
123
|
+
homepage: https://rubygems.org/gems/midi-communications
|
124
|
+
licenses:
|
125
|
+
- LGPL-3.0
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - "~>"
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '2.7'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubygems_version: 3.1.6
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Platform independent realtime MIDI input and output for Ruby
|
146
|
+
test_files: []
|