midi-communications 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|