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.
@@ -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: []