ffi-coremidi 0.3.8 → 0.5.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 +5 -5
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/lib/coremidi/api.rb +45 -51
- data/lib/coremidi/destination.rb +17 -19
- data/lib/coremidi/device.rb +20 -22
- data/lib/coremidi/endpoint.rb +11 -10
- data/lib/coremidi/entity.rb +31 -39
- data/lib/coremidi/source.rb +82 -67
- data/lib/coremidi/type_conversion.rb +8 -9
- data/lib/coremidi.rb +17 -12
- metadata +30 -34
- data/test/helper.rb +0 -66
- data/test/input_buffer_test.rb +0 -42
- data/test/io_test.rb +0 -90
data/lib/coremidi/entity.rb
CHANGED
@@ -1,48 +1,43 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
3
|
+
module CoreMIDI
|
4
|
+
# A MIDI entity can have any number of MIDI endpoints, each of which is a source or destination
|
5
|
+
# of a 16-channel MIDI stream. By grouping a device's endpoints into entities, the system has
|
6
|
+
# enough information for an application to make reasonable default assumptions about how to
|
7
|
+
# communicate in a bi-directional manner with each entity, as is necessary in MIDI librarian
|
7
8
|
# applications.
|
8
9
|
#
|
9
10
|
# https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
|
10
11
|
class Entity
|
11
|
-
|
12
|
-
attr_reader :endpoints,
|
12
|
+
attr_reader :endpoints,
|
13
13
|
:manufacturer,
|
14
14
|
:model,
|
15
15
|
:name,
|
16
16
|
:resource
|
17
|
-
|
17
|
+
|
18
18
|
# @param [FFI::Pointer] resource A pointer to the underlying entity
|
19
19
|
# @param [Hash] options
|
20
20
|
# @option options [Boolean] :include_offline Include offline endpoints in the list
|
21
21
|
def initialize(resource, options = {})
|
22
|
-
@endpoints = {
|
23
|
-
:
|
24
|
-
:
|
22
|
+
@endpoints = {
|
23
|
+
source: [],
|
24
|
+
destination: []
|
25
25
|
}
|
26
26
|
@resource = resource
|
27
27
|
populate(options)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Assign all of this Entity's endpoints an consecutive local id
|
31
|
-
# @param [
|
32
|
-
# @return [
|
31
|
+
# @param [Integer] starting_id
|
32
|
+
# @return [Integer]
|
33
33
|
def populate_endpoint_ids(starting_id)
|
34
|
-
|
35
|
-
@endpoints.values.flatten.each do |endpoint|
|
36
|
-
endpoint.id = counter + starting_id
|
37
|
-
counter += 1
|
38
|
-
end
|
39
|
-
counter
|
34
|
+
@endpoints.values.flatten.map.with_index { |endpoint, index| endpoint.id = index + starting_id }.length
|
40
35
|
end
|
41
|
-
|
36
|
+
|
42
37
|
# Is the entity online?
|
43
38
|
# @return [Boolean]
|
44
39
|
def online?
|
45
|
-
get_int(:offline)
|
40
|
+
get_int(:offline).zero?
|
46
41
|
end
|
47
42
|
|
48
43
|
private
|
@@ -52,54 +47,53 @@ module CoreMIDI
|
|
52
47
|
def get_name
|
53
48
|
"#{@manufacturer} #{@model}"
|
54
49
|
end
|
55
|
-
|
50
|
+
|
56
51
|
# Populate endpoints of a specified type for this entity
|
57
52
|
# @param [Symbol] type The endpoint type eg :source, :destination
|
58
53
|
# @param [Hash] options
|
59
54
|
# @option options [Boolean] :include_offline Include offline endpoints in the list
|
60
|
-
# @return [
|
55
|
+
# @return [Integer]
|
61
56
|
def populate_endpoints_by_type(type, options = {})
|
62
57
|
endpoint_class = Endpoint.get_class(type)
|
63
58
|
num_endpoints = number_of_endpoints(type)
|
64
59
|
(0..num_endpoints).each do |i|
|
65
60
|
endpoint = endpoint_class.new(i, self)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@endpoints[type].size
|
61
|
+
should_include_message = endpoint.online? || options[:include_offline]
|
62
|
+
@endpoints[type] << endpoint if should_include_message
|
63
|
+
end
|
64
|
+
@endpoints[type].size
|
71
65
|
end
|
72
66
|
|
73
67
|
# Populate the endpoints for this entity
|
74
68
|
# @param [Hash] options
|
75
69
|
# @option options [Boolean] :include_offline Include offline endpoints in the list
|
76
|
-
# @return [
|
70
|
+
# @return [Integer]
|
77
71
|
def populate_endpoints(options = {})
|
78
72
|
@endpoints.keys.map { |type| populate_endpoints_by_type(type, options) }.reduce(&:+)
|
79
73
|
end
|
80
|
-
|
74
|
+
|
81
75
|
# The number of endpoints for this entity
|
82
76
|
# @param [Symbol] type The endpoint type eg :source, :destination
|
83
77
|
def number_of_endpoints(type)
|
84
78
|
case type
|
85
|
-
|
86
|
-
|
79
|
+
when :source then API.MIDIEntityGetNumberOfSources(@resource)
|
80
|
+
when :destination then API.MIDIEntityGetNumberOfDestinations(@resource)
|
87
81
|
end
|
88
82
|
end
|
89
|
-
|
83
|
+
|
90
84
|
# A CFString property from the underlying entity
|
91
85
|
# @param [Symbol, String] name The property name
|
92
86
|
# @return [String, nil]
|
93
87
|
def get_string(name)
|
94
88
|
API.get_string(@resource, name)
|
95
89
|
end
|
96
|
-
|
90
|
+
|
97
91
|
# An Integer property from the underlying entity
|
98
92
|
# @param [Symbol, String] name The property name
|
99
|
-
# @return [
|
93
|
+
# @return [Integer, nil]
|
100
94
|
def get_int(name)
|
101
95
|
API.get_int(@resource, name)
|
102
|
-
end
|
96
|
+
end
|
103
97
|
|
104
98
|
# Populate the entity properties from the underlying resource
|
105
99
|
# @param [Hash] options
|
@@ -110,7 +104,5 @@ module CoreMIDI
|
|
110
104
|
@name = get_name
|
111
105
|
populate_endpoints(options)
|
112
106
|
end
|
113
|
-
|
114
107
|
end
|
115
|
-
|
116
108
|
end
|
data/lib/coremidi/source.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# Type of endpoint used for input
|
4
5
|
class Source
|
5
|
-
|
6
6
|
include Endpoint
|
7
7
|
|
8
|
-
|
8
|
+
# The buffer of received messages since instantiation
|
9
|
+
# @return [Array<Hash>]
|
10
|
+
def buffer
|
11
|
+
fill_buffer
|
12
|
+
@buffer
|
13
|
+
end
|
9
14
|
|
10
15
|
#
|
11
16
|
# An array of MIDI event hashes as such:
|
@@ -20,15 +25,9 @@ module CoreMIDI
|
|
20
25
|
#
|
21
26
|
# @return [Array<Hash>]
|
22
27
|
def gets
|
23
|
-
|
24
|
-
# per https://github.com/arirusso/unimidi/issues/20#issuecomment-44761318
|
25
|
-
sleep(0.0001) # patch to prevent 100% CPU issue with some midi controllers
|
26
|
-
end
|
27
|
-
messages = queued_messages
|
28
|
-
@pointer = @buffer.length
|
29
|
-
messages
|
28
|
+
fill_buffer(locking: true)
|
30
29
|
end
|
31
|
-
|
30
|
+
alias read gets
|
32
31
|
|
33
32
|
# Same as Source#gets except that it returns message data as string of hex
|
34
33
|
# digits as such:
|
@@ -46,12 +45,12 @@ module CoreMIDI
|
|
46
45
|
end
|
47
46
|
messages
|
48
47
|
end
|
49
|
-
|
48
|
+
alias gets_bytestr gets_s
|
50
49
|
|
51
50
|
# Enable this the input for use; can be passed a block
|
52
51
|
# @return [Source]
|
53
|
-
def enable(
|
54
|
-
@enabled
|
52
|
+
def enable(_options = {})
|
53
|
+
@enabled ||= true
|
55
54
|
if block_given?
|
56
55
|
begin
|
57
56
|
yield(self)
|
@@ -61,20 +60,20 @@ module CoreMIDI
|
|
61
60
|
end
|
62
61
|
self
|
63
62
|
end
|
64
|
-
|
65
|
-
|
63
|
+
alias open enable
|
64
|
+
alias start enable
|
66
65
|
|
67
66
|
# Close this input
|
68
67
|
# @return [Boolean]
|
69
68
|
def close
|
70
|
-
#error = API.MIDIPortDisconnectSource( @handle, @resource )
|
71
|
-
#raise "MIDIPortDisconnectSource returned error code #{error}" unless error.zero?
|
72
|
-
#error = API.MIDIClientDispose(@handle)
|
73
|
-
#raise "MIDIClientDispose returned error code #{error}" unless error.zero?
|
74
|
-
#error = API.MIDIPortDispose(@handle)
|
75
|
-
#raise "MIDIPortDispose returned error code #{error}" unless error.zero?
|
76
|
-
#error = API.MIDIEndpointDispose(@resource)
|
77
|
-
#raise "MIDIEndpointDispose returned error code #{error}" unless error.zero?
|
69
|
+
# error = API.MIDIPortDisconnectSource( @handle, @resource )
|
70
|
+
# raise "MIDIPortDisconnectSource returned error code #{error}" unless error.zero?
|
71
|
+
# error = API.MIDIClientDispose(@handle)
|
72
|
+
# raise "MIDIClientDispose returned error code #{error}" unless error.zero?
|
73
|
+
# error = API.MIDIPortDispose(@handle)
|
74
|
+
# raise "MIDIPortDispose returned error code #{error}" unless error.zero?
|
75
|
+
# error = API.MIDIEndpointDispose(@resource)
|
76
|
+
# raise "MIDIEndpointDispose returned error code #{error}" unless error.zero?
|
78
77
|
if @enabled
|
79
78
|
@enabled = false
|
80
79
|
true
|
@@ -103,24 +102,49 @@ module CoreMIDI
|
|
103
102
|
|
104
103
|
protected
|
105
104
|
|
105
|
+
def truncate_buffer
|
106
|
+
@buffer.slice!(-1024, 1024)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Migrate new received messages from the callback queue to
|
110
|
+
# the buffer
|
111
|
+
def fill_buffer(locking: nil)
|
112
|
+
locking ||= false
|
113
|
+
|
114
|
+
messages = []
|
115
|
+
|
116
|
+
if locking && @queue.empty?
|
117
|
+
@threads_sync_semaphore.synchronize do
|
118
|
+
@threads_waiting << Thread.current
|
119
|
+
end
|
120
|
+
sleep
|
121
|
+
end
|
122
|
+
|
123
|
+
messages << @queue.pop until @queue.empty?
|
124
|
+
@buffer += messages
|
125
|
+
truncate_buffer
|
126
|
+
@pointer = @buffer.length
|
127
|
+
messages
|
128
|
+
end
|
129
|
+
|
106
130
|
# Base initialization for this endpoint -- done whether or not the endpoint is enabled to check whether
|
107
131
|
# it is truly available for use
|
108
132
|
def connect
|
109
133
|
enable_client
|
110
134
|
initialize_port
|
111
135
|
@resource = API.MIDIEntityGetSource(@entity.resource, @resource_id)
|
112
|
-
error = API.MIDIPortConnectSource(@handle, @resource, nil
|
136
|
+
error = API.MIDIPortConnectSource(@handle, @resource, nil)
|
113
137
|
initialize_buffer
|
138
|
+
@queue = Queue.new
|
114
139
|
@sysex_buffer = []
|
115
|
-
@start_time = Time.now.to_f
|
116
140
|
|
117
141
|
error.zero?
|
118
142
|
end
|
119
|
-
|
143
|
+
alias connect? connect
|
120
144
|
|
121
145
|
private
|
122
146
|
|
123
|
-
# Add a single message to the
|
147
|
+
# Add a single message to the callback queue
|
124
148
|
# @param [Array<Fixnum>] bytes Message data
|
125
149
|
# @param [Float] timestamp The system float timestamp
|
126
150
|
# @return [Array<Hash>] The resulting buffer
|
@@ -132,31 +156,29 @@ module CoreMIDI
|
|
132
156
|
@sysex_buffer.clear
|
133
157
|
end
|
134
158
|
end
|
135
|
-
|
136
|
-
@
|
137
|
-
end
|
159
|
+
message = get_message_formatted(bytes, timestamp)
|
160
|
+
@queue << message
|
138
161
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
162
|
+
@threads_sync_semaphore.synchronize do
|
163
|
+
@threads_waiting.each(&:run)
|
164
|
+
@threads_waiting.clear
|
165
|
+
end
|
143
166
|
|
144
|
-
|
145
|
-
def queued_messages?
|
146
|
-
@pointer < @buffer.length
|
167
|
+
message
|
147
168
|
end
|
148
169
|
|
149
|
-
# The callback fired by coremidi when new MIDI messages are
|
170
|
+
# The callback fired by coremidi when new MIDI messages are received
|
150
171
|
def get_event_callback
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
Thread.main.raise(exception)
|
172
|
+
Thread.abort_on_exception = true
|
173
|
+
proc do |new_packets, _refCon_ptr, _connRefCon_ptr|
|
174
|
+
# p "packets received: #{new_packets[:numPackets]}"
|
175
|
+
timestamp = Time.now.to_f
|
176
|
+
messages = get_messages(new_packets)
|
177
|
+
messages.each do |message|
|
178
|
+
enqueue_message(message, timestamp)
|
159
179
|
end
|
180
|
+
rescue Exception => e
|
181
|
+
Thread.main.raise(e)
|
160
182
|
end
|
161
183
|
end
|
162
184
|
|
@@ -169,18 +191,18 @@ module CoreMIDI
|
|
169
191
|
data = first[:data].to_a
|
170
192
|
messages = []
|
171
193
|
messages << data.slice!(0, first[:length])
|
172
|
-
(count - 1).times do |
|
194
|
+
(count - 1).times do |_i|
|
173
195
|
length_index = find_next_length_index(data)
|
174
196
|
message_length = data[length_index]
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
197
|
+
next if message_length.nil?
|
198
|
+
|
199
|
+
packet_start_index = length_index + 2
|
200
|
+
packet_end_index = packet_start_index + message_length
|
201
|
+
next unless data.length >= packet_end_index + 1
|
202
|
+
|
203
|
+
packet = data.slice!(0..packet_end_index)
|
204
|
+
message = packet.slice(packet_start_index, message_length)
|
205
|
+
messages << message
|
184
206
|
end
|
185
207
|
messages
|
186
208
|
end
|
@@ -203,18 +225,12 @@ module CoreMIDI
|
|
203
225
|
end
|
204
226
|
end
|
205
227
|
|
206
|
-
# Timestamp for a received MIDI message
|
207
|
-
# @return [Fixnum]
|
208
|
-
def timestamp(now)
|
209
|
-
(now - @start_time) * 1000
|
210
|
-
end
|
211
|
-
|
212
228
|
# Give a message its timestamp and package it in a Hash
|
213
229
|
# @return [Hash]
|
214
230
|
def get_message_formatted(raw, time)
|
215
231
|
{
|
216
|
-
:
|
217
|
-
:
|
232
|
+
data: raw,
|
233
|
+
timestamp: time
|
218
234
|
}
|
219
235
|
end
|
220
236
|
|
@@ -225,6 +241,7 @@ module CoreMIDI
|
|
225
241
|
port = API.create_midi_input_port(@client, @resource_id, @name, @callback)
|
226
242
|
@handle = port[:handle]
|
227
243
|
raise "MIDIInputPortCreate returned error code #{port[:error]}" unless port[:error].zero?
|
244
|
+
|
228
245
|
true
|
229
246
|
end
|
230
247
|
|
@@ -239,7 +256,5 @@ module CoreMIDI
|
|
239
256
|
end
|
240
257
|
true
|
241
258
|
end
|
242
|
-
|
243
259
|
end
|
244
|
-
|
245
260
|
end
|
@@ -1,21 +1,20 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module CoreMIDI
|
4
|
+
# Helper for converting MIDI data
|
4
5
|
module TypeConversion
|
5
|
-
|
6
|
-
extend self
|
6
|
+
module_function
|
7
7
|
|
8
8
|
# Convert an array of numeric byes to a hex string (e.g. [0x90, 0x40, 0x40] becomes "904040")
|
9
|
-
# @param [Array<
|
9
|
+
# @param [Array<Integer>] bytes
|
10
10
|
# @return [String]
|
11
11
|
def numeric_bytes_to_hex_string(bytes)
|
12
|
-
string_bytes = bytes.map do |byte|
|
12
|
+
string_bytes = bytes.map do |byte|
|
13
13
|
str = byte.to_s(16).upcase
|
14
|
-
str = "0"
|
14
|
+
str = "0#{str}" if byte < 16
|
15
15
|
str
|
16
16
|
end
|
17
17
|
string_bytes.join
|
18
|
-
end
|
19
|
-
|
18
|
+
end
|
20
19
|
end
|
21
20
|
end
|
data/lib/coremidi.rb
CHANGED
@@ -1,23 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
4
|
+
# ffi-coremidi
|
3
5
|
# Realtime MIDI IO with Ruby for OSX
|
4
|
-
#
|
6
|
+
#
|
7
|
+
# (c)2011-2022 Ari Russo
|
8
|
+
# https://github.com/arirusso/ffi-coremidi
|
9
|
+
#
|
5
10
|
|
6
11
|
# Libs
|
7
|
-
require
|
8
|
-
require
|
12
|
+
require 'ffi'
|
13
|
+
require 'forwardable'
|
9
14
|
|
10
15
|
# Modules
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
16
|
+
require 'coremidi/api'
|
17
|
+
require 'coremidi/endpoint'
|
18
|
+
require 'coremidi/type_conversion'
|
14
19
|
|
15
20
|
# Classes
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
21
|
+
require 'coremidi/entity'
|
22
|
+
require 'coremidi/device'
|
23
|
+
require 'coremidi/source'
|
24
|
+
require 'coremidi/destination'
|
20
25
|
|
21
26
|
module CoreMIDI
|
22
|
-
VERSION =
|
27
|
+
VERSION = '0.5.0'
|
23
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-coremidi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ari Russo
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -16,100 +16,100 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5.
|
19
|
+
version: '5.15'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 5.
|
22
|
+
version: 5.15.0
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '5.
|
29
|
+
version: '5.15'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.
|
32
|
+
version: 5.15.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: rake
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '13.0'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 13.0.6
|
43
43
|
type: :development
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
49
|
+
version: '13.0'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
52
|
+
version: 13.0.6
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
|
-
name:
|
54
|
+
name: rspec
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
59
|
+
version: '3.11'
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
62
|
+
version: 3.11.0
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '3.11'
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version:
|
72
|
+
version: 3.11.0
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
|
-
name:
|
74
|
+
name: rubocop
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
77
|
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: '1.
|
79
|
+
version: '1.25'
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: 1.25.1
|
83
83
|
type: :development
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '1.
|
89
|
+
version: '1.25'
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 1.
|
92
|
+
version: 1.25.1
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: ffi
|
95
95
|
requirement: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
97
|
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: '1.
|
99
|
+
version: '1.15'
|
100
100
|
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 1.
|
102
|
+
version: 1.15.5
|
103
103
|
type: :runtime
|
104
104
|
prerelease: false
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '1.
|
109
|
+
version: '1.15'
|
110
110
|
- - ">="
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version: 1.
|
112
|
+
version: 1.15.5
|
113
113
|
description: Perform realtime MIDI IO with Ruby for OSX
|
114
114
|
email:
|
115
115
|
- ari.russo@gmail.com
|
@@ -127,14 +127,11 @@ files:
|
|
127
127
|
- lib/coremidi/entity.rb
|
128
128
|
- lib/coremidi/source.rb
|
129
129
|
- lib/coremidi/type_conversion.rb
|
130
|
-
- test/helper.rb
|
131
|
-
- test/input_buffer_test.rb
|
132
|
-
- test/io_test.rb
|
133
130
|
homepage: http://github.com/arirusso/ffi-coremidi
|
134
131
|
licenses:
|
135
|
-
- Apache
|
132
|
+
- Apache-2.0
|
136
133
|
metadata: {}
|
137
|
-
post_install_message:
|
134
|
+
post_install_message:
|
138
135
|
rdoc_options: []
|
139
136
|
require_paths:
|
140
137
|
- lib
|
@@ -149,9 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
146
|
- !ruby/object:Gem::Version
|
150
147
|
version: 1.3.6
|
151
148
|
requirements: []
|
152
|
-
|
153
|
-
|
154
|
-
signing_key:
|
149
|
+
rubygems_version: 3.3.3
|
150
|
+
signing_key:
|
155
151
|
specification_version: 4
|
156
152
|
summary: Realtime MIDI IO with Ruby for OSX
|
157
153
|
test_files: []
|