ffi-coremidi 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/lib/coremidi/api.rb +44 -50
- data/lib/coremidi/destination.rb +14 -16
- data/lib/coremidi/device.rb +11 -13
- data/lib/coremidi/endpoint.rb +6 -5
- data/lib/coremidi/entity.rb +8 -16
- data/lib/coremidi/source.rb +59 -53
- data/lib/coremidi/type_conversion.rb +6 -7
- data/lib/coremidi.rb +13 -11
- metadata +29 -33
- data/test/helper.rb +0 -66
- data/test/input_buffer_test.rb +0 -42
- data/test/io_test.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d05cb8f763c856b651e7fa5f94499350bc7576cd210e7402ce26bc9bbd714739
|
4
|
+
data.tar.gz: 77a98c6abc53d0287bc4e57d7f3cce217da9e32d73fd6a3205602f0c6bd69fbe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc172a0d02c6fc6efd3d1337623e92fdf9bb4b01e08debe2105ed78bb306d49db44308d72cc0041cd04ee04ecb50f4ebda935610bcf18dab67afb2b90e1a5d9b
|
7
|
+
data.tar.gz: bbdcf6d8e87f2896db09859e79b6d8c39f33ea2046a10704d917439d7974e50224ed842414ece048e99d671943da7939e47cef74ae3e4683ee4ccdf54646687b
|
data/LICENSE
CHANGED
data/README.md
CHANGED
data/lib/coremidi/api.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# Coremidi C binding
|
4
5
|
module API
|
5
|
-
|
6
6
|
extend FFI::Library
|
7
7
|
ffi_lib '/System/Library/Frameworks/CoreMIDI.framework/Versions/Current/CoreMIDI'
|
8
8
|
|
@@ -17,12 +17,11 @@ module CoreMIDI
|
|
17
17
|
typedef :pointer, :MIDIEntityRef
|
18
18
|
typedef :pointer, :MIDIObjectRef
|
19
19
|
typedef :pointer, :MIDIPortRef
|
20
|
-
#typedef :pointer, :MIDIReadProc
|
20
|
+
# typedef :pointer, :MIDIReadProc
|
21
21
|
typedef :uint32, :MIDITimeStamp
|
22
22
|
typedef :int32, :OSStatus
|
23
23
|
|
24
24
|
class MIDISysexSendRequest < FFI::Struct
|
25
|
-
|
26
25
|
layout :destination, :MIDIEndpointRef,
|
27
26
|
:data, :pointer,
|
28
27
|
:bytes_to_send, :uint32,
|
@@ -33,18 +32,15 @@ module CoreMIDI
|
|
33
32
|
end
|
34
33
|
|
35
34
|
class MIDIPacket < FFI::Struct
|
36
|
-
|
37
35
|
layout :timestamp, :MIDITimeStamp,
|
38
36
|
:nothing, :uint32, # no idea...
|
39
37
|
:length, :uint16,
|
40
38
|
:data, [:uint8, 256]
|
41
|
-
|
42
39
|
end
|
43
40
|
|
44
41
|
class MIDIPacketList < FFI::Struct
|
45
42
|
layout :numPackets, :uint32,
|
46
43
|
:packet, [MIDIPacket.by_value, 1]
|
47
|
-
|
48
44
|
end
|
49
45
|
|
50
46
|
def self.get_callback(*args, &block)
|
@@ -53,7 +49,7 @@ module CoreMIDI
|
|
53
49
|
|
54
50
|
# Pack the given data into a coremidi MIDI packet (used by Destination)
|
55
51
|
def self.get_midi_packet(data)
|
56
|
-
format =
|
52
|
+
format = 'C' * data.size
|
57
53
|
packed_data = data.pack(format)
|
58
54
|
char_size = FFI.type_size(:char) * data.size
|
59
55
|
bytes = FFI::MemoryPointer.new(char_size)
|
@@ -67,8 +63,8 @@ module CoreMIDI
|
|
67
63
|
error = API.MIDIClientCreate(client_name, nil, nil, client_pointer)
|
68
64
|
client = client_pointer.read_pointer
|
69
65
|
{
|
70
|
-
:
|
71
|
-
:
|
66
|
+
error: error,
|
67
|
+
resource: client
|
72
68
|
}
|
73
69
|
end
|
74
70
|
|
@@ -78,8 +74,8 @@ module CoreMIDI
|
|
78
74
|
error = API.MIDIInputPortCreate(client, port_name, callback, nil, handle_ptr)
|
79
75
|
handle = handle_ptr.read_pointer
|
80
76
|
{
|
81
|
-
:
|
82
|
-
:
|
77
|
+
error: error,
|
78
|
+
handle: handle
|
83
79
|
}
|
84
80
|
end
|
85
81
|
|
@@ -89,8 +85,8 @@ module CoreMIDI
|
|
89
85
|
error = API.MIDIOutputPortCreate(client, port_name, port_pointer)
|
90
86
|
handle = port_pointer.read_pointer
|
91
87
|
{
|
92
|
-
:
|
93
|
-
:
|
88
|
+
error: error,
|
89
|
+
handle: handle
|
94
90
|
}
|
95
91
|
end
|
96
92
|
|
@@ -100,11 +96,12 @@ module CoreMIDI
|
|
100
96
|
packet_ptr = API.MIDIPacketListInit(packet_list)
|
101
97
|
time = HostTime.AudioGetCurrentHostTime
|
102
98
|
packet_ptr = if X86_64
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
99
|
+
API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time, size, bytes)
|
100
|
+
else
|
101
|
+
# Pass in two 32-bit 0s for the 64 bit time
|
102
|
+
time1 = API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time >> 32, time & 0xFFFFFFFF, size,
|
103
|
+
bytes)
|
104
|
+
end
|
108
105
|
packet_list
|
109
106
|
end
|
110
107
|
|
@@ -132,7 +129,7 @@ module CoreMIDI
|
|
132
129
|
bytes = FFI::MemoryPointer.new(length + 1)
|
133
130
|
|
134
131
|
if CF.CFStringGetCString(string, bytes, length + 1, :kCFStringEncodingUTF8)
|
135
|
-
bytes.read_string.force_encoding(
|
132
|
+
bytes.read_string.force_encoding('utf-8')
|
136
133
|
end
|
137
134
|
ensure
|
138
135
|
CF.CFRelease(string) unless string.nil? || string.null?
|
@@ -145,13 +142,13 @@ module CoreMIDI
|
|
145
142
|
callback :MIDIReadProc, [MIDIPacketList.by_ref, :pointer, :pointer], :pointer
|
146
143
|
|
147
144
|
# OSStatus MIDIClientCreate(CFStringRef name, MIDINotifyProc notifyProc, void *notifyRefCon, MIDIClientRef *outClient);
|
148
|
-
attach_function :MIDIClientCreate, [
|
145
|
+
attach_function :MIDIClientCreate, %i[pointer pointer pointer pointer], :int
|
149
146
|
|
150
147
|
# OSStatus MIDIClientDispose(MIDIClientRef client);
|
151
148
|
attach_function :MIDIClientDispose, [:pointer], :int
|
152
149
|
|
153
150
|
# MIDIEntityRef MIDIDeviceGetEntity(MIDIDeviceRef device, ItemCount entityIndex0);
|
154
|
-
attach_function :MIDIDeviceGetEntity, [
|
151
|
+
attach_function :MIDIDeviceGetEntity, %i[MIDIDeviceRef ItemCount], :MIDIEntityRef
|
155
152
|
|
156
153
|
# MIDIEndpointRef MIDIGetDestination(ItemCount destIndex0);
|
157
154
|
attach_function :MIDIGetNumberOfDestinations, [], :ItemCount
|
@@ -162,11 +159,11 @@ module CoreMIDI
|
|
162
159
|
# MIDIEndpointRef MIDIEntityGetDestination(MIDIEntityRef entity, ItemCount destIndex0);
|
163
160
|
attach_function :MIDIGetDestination, [:int], :pointer
|
164
161
|
|
165
|
-
#extern OSStatus MIDIEndpointDispose( MIDIEndpointRef endpt );
|
162
|
+
# extern OSStatus MIDIEndpointDispose( MIDIEndpointRef endpt );
|
166
163
|
attach_function :MIDIEndpointDispose, [:MIDIEndpointRef], :OSStatus
|
167
164
|
|
168
165
|
# MIDIEndpointRef MIDIEntityGetDestination( MIDIEntityRef entity, ItemCount destIndex0 );
|
169
|
-
attach_function :MIDIEntityGetDestination, [
|
166
|
+
attach_function :MIDIEntityGetDestination, %i[MIDIEntityRef int], :MIDIEndpointRef
|
170
167
|
|
171
168
|
# ItemCount MIDIEntityGetNumberOfDestinations (MIDIEntityRef entity);
|
172
169
|
attach_function :MIDIEntityGetNumberOfDestinations, [:MIDIEntityRef], :ItemCount
|
@@ -175,77 +172,76 @@ module CoreMIDI
|
|
175
172
|
attach_function :MIDIEntityGetNumberOfSources, [:MIDIEntityRef], :ItemCount
|
176
173
|
|
177
174
|
# MIDIEndpointRef MIDIEntityGetSource (MIDIEntityRef entity, ItemCount sourceIndex0);
|
178
|
-
attach_function :MIDIEntityGetSource, [
|
175
|
+
attach_function :MIDIEntityGetSource, %i[MIDIEntityRef ItemCount], :MIDIEndpointRef
|
179
176
|
|
180
177
|
# MIDIDeviceRef MIDIGetDevice(ItemCount deviceIndex0);
|
181
178
|
attach_function :MIDIGetDevice, [:ItemCount], :MIDIDeviceRef
|
182
179
|
|
183
180
|
# extern OSStatus MIDIInputPortCreate( MIDIClientRef client, CFStringRef portName,
|
184
181
|
# MIDIReadProc readProc, void * refCon, MIDIPortRef * outPort );
|
185
|
-
attach_function :MIDIInputPortCreate, [
|
182
|
+
attach_function :MIDIInputPortCreate, %i[MIDIClientRef CFStringRef MIDIReadProc pointer MIDIPortRef],
|
183
|
+
:OSStatus
|
186
184
|
|
187
185
|
# extern OSStatus MIDIObjectGetIntegerProperty( MIDIObjectRef obj, CFStringRef propertyID, SInt32 * outValue );
|
188
|
-
attach_function :MIDIObjectGetIntegerProperty, [
|
186
|
+
attach_function :MIDIObjectGetIntegerProperty, %i[MIDIObjectRef CFStringRef pointer], :OSStatus
|
189
187
|
|
190
188
|
# OSStatus MIDIObjectGetStringProperty (MIDIObjectRef obj, CFStringRef propertyID, CFStringRef *str);
|
191
|
-
attach_function :MIDIObjectGetStringProperty, [
|
189
|
+
attach_function :MIDIObjectGetStringProperty, %i[MIDIObjectRef CFStringRef pointer], :OSStatus
|
192
190
|
|
193
191
|
# extern OSStatus MIDIOutputPortCreate( MIDIClientRef client, CFStringRef portName, MIDIPortRef * outPort );
|
194
|
-
attach_function :MIDIOutputPortCreate, [
|
192
|
+
attach_function :MIDIOutputPortCreate, %i[MIDIClientRef CFStringRef pointer], :int
|
195
193
|
|
196
194
|
# (MIDIPacket*) MIDIPacketListInit(MIDIPacketList *pktlist);
|
197
195
|
attach_function :MIDIPacketListInit, [:pointer], :pointer
|
198
196
|
|
199
|
-
#extern OSStatus MIDIPortConnectSource( MIDIPortRef port, MIDIEndpointRef source, void * connRefCon )
|
200
|
-
attach_function :MIDIPortConnectSource, [
|
197
|
+
# extern OSStatus MIDIPortConnectSource( MIDIPortRef port, MIDIEndpointRef source, void * connRefCon )
|
198
|
+
attach_function :MIDIPortConnectSource, %i[MIDIPortRef MIDIEndpointRef pointer], :OSStatus
|
201
199
|
|
202
|
-
#extern OSStatus MIDIPortDisconnectSource( MIDIPortRef port, MIDIEndpointRef source );
|
203
|
-
attach_function :MIDIPortDisconnectSource, [
|
200
|
+
# extern OSStatus MIDIPortDisconnectSource( MIDIPortRef port, MIDIEndpointRef source );
|
201
|
+
attach_function :MIDIPortDisconnectSource, %i[MIDIPortRef MIDIEndpointRef], :OSStatus
|
204
202
|
|
205
|
-
#extern OSStatus MIDIPortDispose(MIDIPortRef port );
|
203
|
+
# extern OSStatus MIDIPortDispose(MIDIPortRef port );
|
206
204
|
attach_function :MIDIPortDispose, [:MIDIPortRef], :OSStatus
|
207
205
|
|
208
|
-
#extern OSStatus MIDISend(MIDIPortRef port,MIDIEndpointRef dest,const MIDIPacketList *pktlist);
|
209
|
-
attach_function :MIDISend, [
|
206
|
+
# extern OSStatus MIDISend(MIDIPortRef port,MIDIEndpointRef dest,const MIDIPacketList *pktlist);
|
207
|
+
attach_function :MIDISend, %i[MIDIPortRef MIDIEndpointRef pointer], :int
|
210
208
|
|
211
|
-
#OSStatus MIDISendSysex(MIDISysexSendRequest *request);
|
209
|
+
# OSStatus MIDISendSysex(MIDISysexSendRequest *request);
|
212
210
|
attach_function :MIDISendSysex, [:pointer], :int
|
213
211
|
|
214
212
|
# extern MIDIPacket * MIDIPacketListAdd( MIDIPacketList * pktlist, ByteCount listSize,
|
215
213
|
# MIDIPacket * curPacket, MIDITimeStamp time,
|
216
214
|
# ByteCount nData, const Byte * data)
|
217
215
|
if X86_64
|
218
|
-
attach_function :MIDIPacketListAdd, [
|
216
|
+
attach_function :MIDIPacketListAdd, %i[pointer int pointer uint64 int pointer], :pointer
|
219
217
|
else
|
220
|
-
attach_function :MIDIPacketListAdd, [
|
218
|
+
attach_function :MIDIPacketListAdd, %i[pointer int pointer int int int pointer], :pointer
|
221
219
|
end
|
222
220
|
|
223
221
|
module CF
|
224
|
-
|
225
222
|
extend FFI::Library
|
226
223
|
ffi_lib '/System/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation'
|
227
224
|
|
228
225
|
typedef :pointer, :CFStringRef
|
229
226
|
typedef :long, :CFIndex
|
230
|
-
enum :CFStringEncoding, [
|
227
|
+
enum :CFStringEncoding, [:kCFStringEncodingUTF8, 0x08000100]
|
231
228
|
|
232
229
|
# CFString* CFStringCreateWithCString( ?, CString, encoding)
|
233
|
-
attach_function :CFStringCreateWithCString, [
|
230
|
+
attach_function :CFStringCreateWithCString, %i[pointer string int], :pointer
|
234
231
|
# CString* CFStringGetCStringPtr(CFString*, encoding)
|
235
|
-
attach_function :CFStringGetCStringPtr, [
|
232
|
+
attach_function :CFStringGetCStringPtr, %i[pointer int], :pointer
|
236
233
|
|
237
234
|
# CFIndex CFStringGetLength(CFStringRef theString);
|
238
|
-
attach_function :CFStringGetLength, [
|
235
|
+
attach_function :CFStringGetLength, [:CFStringRef], :CFIndex
|
239
236
|
|
240
237
|
# CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encoding);
|
241
|
-
attach_function :CFStringGetMaximumSizeForEncoding, [
|
238
|
+
attach_function :CFStringGetMaximumSizeForEncoding, %i[CFIndex CFStringEncoding], :long
|
242
239
|
|
243
240
|
# Boolean CFStringGetCString(CFStringRef theString, char *buffer, CFIndex bufferSize, CFStringEncoding encoding);
|
244
|
-
attach_function :CFStringGetCString, [
|
241
|
+
attach_function :CFStringGetCString, %i[CFStringRef pointer CFIndex CFStringEncoding], :bool
|
245
242
|
|
246
243
|
# void CFRelease (CFTypeRef cf);
|
247
|
-
attach_function :CFRelease, [
|
248
|
-
|
244
|
+
attach_function :CFRelease, [:pointer], :void
|
249
245
|
end
|
250
246
|
|
251
247
|
module HostTime
|
@@ -257,7 +253,5 @@ module CoreMIDI
|
|
257
253
|
# UInt64 AudioGetCurrentHostTime()
|
258
254
|
attach_function :AudioGetCurrentHostTime, [], :uint64
|
259
255
|
end
|
260
|
-
|
261
256
|
end
|
262
|
-
|
263
257
|
end
|
data/lib/coremidi/destination.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# Type of endpoint used for output
|
4
5
|
class Destination
|
5
|
-
|
6
6
|
include Endpoint
|
7
7
|
|
8
8
|
attr_reader :entity
|
@@ -24,14 +24,14 @@ module CoreMIDI
|
|
24
24
|
def puts_s(data)
|
25
25
|
data = data.dup
|
26
26
|
bytes = []
|
27
|
-
until (str = data.slice!(0,2)).eql?(
|
27
|
+
until (str = data.slice!(0, 2)).eql?('')
|
28
28
|
bytes << str.hex
|
29
29
|
end
|
30
30
|
puts_bytes(*bytes)
|
31
31
|
true
|
32
32
|
end
|
33
|
-
|
34
|
-
|
33
|
+
alias puts_bytestr puts_s
|
34
|
+
alias puts_hex puts_s
|
35
35
|
|
36
36
|
# Send a MIDI message comprised of numeric bytes
|
37
37
|
# @param [*Integer] data Numeric bytes eg 0x90, 0x40, 0x40
|
@@ -39,7 +39,7 @@ module CoreMIDI
|
|
39
39
|
def puts_bytes(*data)
|
40
40
|
type = sysex?(data) ? :sysex : :small
|
41
41
|
bytes = API.get_midi_packet(data)
|
42
|
-
send("puts_#{type
|
42
|
+
send("puts_#{type}", bytes, data.size)
|
43
43
|
true
|
44
44
|
end
|
45
45
|
|
@@ -53,12 +53,12 @@ module CoreMIDI
|
|
53
53
|
when String then puts_bytestr(*args)
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
alias write puts
|
57
57
|
|
58
58
|
# Enable this device
|
59
59
|
# @return [Destination]
|
60
|
-
def enable(
|
61
|
-
@enabled
|
60
|
+
def enable(_options = {})
|
61
|
+
@enabled ||= true
|
62
62
|
if block_given?
|
63
63
|
begin
|
64
64
|
yield(self)
|
@@ -68,8 +68,8 @@ module CoreMIDI
|
|
68
68
|
end
|
69
69
|
self
|
70
70
|
end
|
71
|
-
|
72
|
-
|
71
|
+
alias open enable
|
72
|
+
alias start enable
|
73
73
|
|
74
74
|
# Shortcut to the first output endpoint available
|
75
75
|
# @return [Destination]
|
@@ -97,10 +97,10 @@ module CoreMIDI
|
|
97
97
|
def connect
|
98
98
|
client_error = enable_client
|
99
99
|
port_error = initialize_port
|
100
|
-
@resource = API.MIDIEntityGetDestination(
|
100
|
+
@resource = API.MIDIEntityGetDestination(@entity.resource, @resource_id)
|
101
101
|
!@resource.address.zero? && client_error.zero? && port_error.zero?
|
102
102
|
end
|
103
|
-
|
103
|
+
alias connect? connect
|
104
104
|
|
105
105
|
private
|
106
106
|
|
@@ -126,7 +126,7 @@ module CoreMIDI
|
|
126
126
|
|
127
127
|
SysexCompletionCallback =
|
128
128
|
API.get_callback([:pointer]) do |sysex_request_ptr|
|
129
|
-
|
129
|
+
# this isn't working for some reason. as of now, it's not needed though
|
130
130
|
end
|
131
131
|
|
132
132
|
# Initialize a coremidi port for this endpoint
|
@@ -140,7 +140,5 @@ module CoreMIDI
|
|
140
140
|
def sysex?(data)
|
141
141
|
data.first.eql?(0xF0) && data.last.eql?(0xF7)
|
142
142
|
end
|
143
|
-
|
144
143
|
end
|
145
|
-
|
146
144
|
end
|
data/lib/coremidi/device.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# A MIDI device may have multiple logically distinct sub-components. For example, one device may
|
4
5
|
# encompass a MIDI synthesizer and a pair of MIDI ports, both addressable via a USB port. Each
|
5
6
|
# such element of a device is called a MIDI entity.
|
6
7
|
#
|
7
8
|
# https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
|
8
9
|
class Device
|
9
|
-
|
10
10
|
attr_reader :entities,
|
11
11
|
:id, # Unique Numeric id
|
12
12
|
:name # Device name from coremidi
|
@@ -25,8 +25,8 @@ module CoreMIDI
|
|
25
25
|
# Endpoints for this device
|
26
26
|
# @return [Array<Endpoint>]
|
27
27
|
def endpoints
|
28
|
-
endpoints = { :
|
29
|
-
endpoints.
|
28
|
+
endpoints = { source: [], destination: [] }
|
29
|
+
endpoints.each_key do |key|
|
30
30
|
endpoint_group = entities.map { |entity| entity.endpoints[key] }.flatten
|
31
31
|
endpoints[key] += endpoint_group
|
32
32
|
end
|
@@ -53,8 +53,8 @@ module CoreMIDI
|
|
53
53
|
if !populated? || !use_cache
|
54
54
|
@devices = []
|
55
55
|
counter = 0
|
56
|
-
|
57
|
-
device = new(counter, device_pointer, :
|
56
|
+
until (device_pointer = API.MIDIGetDevice(counter)).null?
|
57
|
+
device = new(counter, device_pointer, include_offline: include_offline)
|
58
58
|
@devices << device
|
59
59
|
counter += 1
|
60
60
|
end
|
@@ -79,8 +79,8 @@ module CoreMIDI
|
|
79
79
|
|
80
80
|
# Populate the device name
|
81
81
|
def populate_name
|
82
|
-
@name = API.get_string(@resource,
|
83
|
-
raise
|
82
|
+
@name = API.get_string(@resource, 'name')
|
83
|
+
raise "Can't get device name" unless @name
|
84
84
|
end
|
85
85
|
|
86
86
|
# All of the endpoints for all devices a consecutive local id
|
@@ -97,8 +97,8 @@ module CoreMIDI
|
|
97
97
|
def populate_entities(options = {})
|
98
98
|
include_if_offline = options[:include_offline] || false
|
99
99
|
i = 0
|
100
|
-
|
101
|
-
@entities << Entity.new(entity_pointer, :
|
100
|
+
until (entity_pointer = API.MIDIDeviceGetEntity(@resource, i)).null?
|
101
|
+
@entities << Entity.new(entity_pointer, include_offline: include_if_offline)
|
102
102
|
i += 1
|
103
103
|
end
|
104
104
|
i
|
@@ -107,9 +107,7 @@ module CoreMIDI
|
|
107
107
|
# Populate the instance
|
108
108
|
def populate(options = {})
|
109
109
|
populate_name
|
110
|
-
populate_entities(:
|
110
|
+
populate_entities(include_offline: options[:include_offline])
|
111
111
|
end
|
112
|
-
|
113
112
|
end
|
114
|
-
|
115
113
|
end
|
data/lib/coremidi/endpoint.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# A source or destination of a 16-channel MIDI stream
|
4
5
|
#
|
5
6
|
# https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
|
6
7
|
module Endpoint
|
7
|
-
|
8
8
|
extend Forwardable
|
9
9
|
|
10
10
|
attr_reader :enabled, # has the endpoint been initialized?
|
@@ -15,7 +15,7 @@ module CoreMIDI
|
|
15
15
|
|
16
16
|
def_delegators :entity, :manufacturer, :model, :name
|
17
17
|
|
18
|
-
|
18
|
+
alias enabled? enabled
|
19
19
|
|
20
20
|
# @param [Integer] resource_id
|
21
21
|
# @param [Entity] entity
|
@@ -24,6 +24,9 @@ module CoreMIDI
|
|
24
24
|
@resource_id = resource_id
|
25
25
|
@type = get_type
|
26
26
|
@enabled = false
|
27
|
+
|
28
|
+
@threads_sync_semaphore = Mutex.new
|
29
|
+
@threads_waiting = []
|
27
30
|
end
|
28
31
|
|
29
32
|
# Is this endpoint online?
|
@@ -102,7 +105,5 @@ module CoreMIDI
|
|
102
105
|
@client = client[:resource]
|
103
106
|
client[:error]
|
104
107
|
end
|
105
|
-
|
106
108
|
end
|
107
|
-
|
108
109
|
end
|
data/lib/coremidi/entity.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CoreMIDI
|
3
4
|
# A MIDI entity can have any number of MIDI endpoints, each of which is a source or destination
|
4
5
|
# of a 16-channel MIDI stream. By grouping a device's endpoints into entities, the system has
|
5
6
|
# enough information for an application to make reasonable default assumptions about how to
|
@@ -8,7 +9,6 @@ module CoreMIDI
|
|
8
9
|
#
|
9
10
|
# https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
|
10
11
|
class Entity
|
11
|
-
|
12
12
|
attr_reader :endpoints,
|
13
13
|
:manufacturer,
|
14
14
|
:model,
|
@@ -31,18 +31,13 @@ module CoreMIDI
|
|
31
31
|
# @param [Integer] starting_id
|
32
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
|
@@ -63,9 +58,8 @@ module CoreMIDI
|
|
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
|
-
end
|
61
|
+
should_include_message = endpoint.online? || options[:include_offline]
|
62
|
+
@endpoints[type] << endpoint if should_include_message
|
69
63
|
end
|
70
64
|
@endpoints[type].size
|
71
65
|
end
|
@@ -82,8 +76,8 @@ module CoreMIDI
|
|
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
|
|
@@ -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,8 +1,8 @@
|
|
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
|
@@ -25,9 +25,9 @@ module CoreMIDI
|
|
25
25
|
#
|
26
26
|
# @return [Array<Hash>]
|
27
27
|
def gets
|
28
|
-
fill_buffer
|
28
|
+
fill_buffer(locking: true)
|
29
29
|
end
|
30
|
-
|
30
|
+
alias read gets
|
31
31
|
|
32
32
|
# Same as Source#gets except that it returns message data as string of hex
|
33
33
|
# digits as such:
|
@@ -45,12 +45,12 @@ module CoreMIDI
|
|
45
45
|
end
|
46
46
|
messages
|
47
47
|
end
|
48
|
-
|
48
|
+
alias gets_bytestr gets_s
|
49
49
|
|
50
50
|
# Enable this the input for use; can be passed a block
|
51
51
|
# @return [Source]
|
52
|
-
def enable(
|
53
|
-
@enabled
|
52
|
+
def enable(_options = {})
|
53
|
+
@enabled ||= true
|
54
54
|
if block_given?
|
55
55
|
begin
|
56
56
|
yield(self)
|
@@ -60,20 +60,20 @@ module CoreMIDI
|
|
60
60
|
end
|
61
61
|
self
|
62
62
|
end
|
63
|
-
|
64
|
-
|
63
|
+
alias open enable
|
64
|
+
alias start enable
|
65
65
|
|
66
66
|
# Close this input
|
67
67
|
# @return [Boolean]
|
68
68
|
def close
|
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?
|
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?
|
77
77
|
if @enabled
|
78
78
|
@enabled = false
|
79
79
|
true
|
@@ -102,14 +102,27 @@ module CoreMIDI
|
|
102
102
|
|
103
103
|
protected
|
104
104
|
|
105
|
+
def truncate_buffer
|
106
|
+
@buffer.slice!(-1024, 1024)
|
107
|
+
end
|
108
|
+
|
105
109
|
# Migrate new received messages from the callback queue to
|
106
110
|
# the buffer
|
107
|
-
def fill_buffer
|
111
|
+
def fill_buffer(locking: nil)
|
112
|
+
locking ||= false
|
113
|
+
|
108
114
|
messages = []
|
109
|
-
|
110
|
-
|
115
|
+
|
116
|
+
if locking && @queue.empty?
|
117
|
+
@threads_sync_semaphore.synchronize do
|
118
|
+
@threads_waiting << Thread.current
|
119
|
+
end
|
120
|
+
sleep
|
111
121
|
end
|
122
|
+
|
123
|
+
messages << @queue.pop until @queue.empty?
|
112
124
|
@buffer += messages
|
125
|
+
truncate_buffer
|
113
126
|
@pointer = @buffer.length
|
114
127
|
messages
|
115
128
|
end
|
@@ -120,14 +133,14 @@ module CoreMIDI
|
|
120
133
|
enable_client
|
121
134
|
initialize_port
|
122
135
|
@resource = API.MIDIEntityGetSource(@entity.resource, @resource_id)
|
123
|
-
error = API.MIDIPortConnectSource(@handle, @resource, nil
|
136
|
+
error = API.MIDIPortConnectSource(@handle, @resource, nil)
|
124
137
|
initialize_buffer
|
125
138
|
@queue = Queue.new
|
126
139
|
@sysex_buffer = []
|
127
140
|
|
128
141
|
error.zero?
|
129
142
|
end
|
130
|
-
|
143
|
+
alias connect? connect
|
131
144
|
|
132
145
|
private
|
133
146
|
|
@@ -145,33 +158,27 @@ module CoreMIDI
|
|
145
158
|
end
|
146
159
|
message = get_message_formatted(bytes, timestamp)
|
147
160
|
@queue << message
|
148
|
-
message
|
149
|
-
end
|
150
161
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
162
|
+
@threads_sync_semaphore.synchronize do
|
163
|
+
@threads_waiting.each(&:run)
|
164
|
+
@threads_waiting.clear
|
165
|
+
end
|
155
166
|
|
156
|
-
|
157
|
-
def queued_messages?
|
158
|
-
!@queue.empty?
|
167
|
+
message
|
159
168
|
end
|
160
169
|
|
161
170
|
# The callback fired by coremidi when new MIDI messages are received
|
162
171
|
def get_event_callback
|
163
172
|
Thread.abort_on_exception = true
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
enqueue_message(message, timestamp)
|
171
|
-
end
|
172
|
-
rescue Exception => exception
|
173
|
-
Thread.main.raise(exception)
|
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)
|
174
179
|
end
|
180
|
+
rescue Exception => e
|
181
|
+
Thread.main.raise(e)
|
175
182
|
end
|
176
183
|
end
|
177
184
|
|
@@ -184,18 +191,18 @@ module CoreMIDI
|
|
184
191
|
data = first[:data].to_a
|
185
192
|
messages = []
|
186
193
|
messages << data.slice!(0, first[:length])
|
187
|
-
(count - 1).times do |
|
194
|
+
(count - 1).times do |_i|
|
188
195
|
length_index = find_next_length_index(data)
|
189
196
|
message_length = data[length_index]
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
199
206
|
end
|
200
207
|
messages
|
201
208
|
end
|
@@ -234,6 +241,7 @@ module CoreMIDI
|
|
234
241
|
port = API.create_midi_input_port(@client, @resource_id, @name, @callback)
|
235
242
|
@handle = port[:handle]
|
236
243
|
raise "MIDIInputPortCreate returned error code #{port[:error]}" unless port[:error].zero?
|
244
|
+
|
237
245
|
true
|
238
246
|
end
|
239
247
|
|
@@ -248,7 +256,5 @@ module CoreMIDI
|
|
248
256
|
end
|
249
257
|
true
|
250
258
|
end
|
251
|
-
|
252
259
|
end
|
253
|
-
|
254
260
|
end
|
@@ -1,9 +1,9 @@
|
|
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
9
|
# @param [Array<Integer>] bytes
|
@@ -11,11 +11,10 @@ module CoreMIDI
|
|
11
11
|
def numeric_bytes_to_hex_string(bytes)
|
12
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,26 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
#
|
2
4
|
# ffi-coremidi
|
3
5
|
# Realtime MIDI IO with Ruby for OSX
|
4
6
|
#
|
5
|
-
# (c)2011-
|
7
|
+
# (c)2011-2022 Ari Russo
|
6
8
|
# https://github.com/arirusso/ffi-coremidi
|
7
9
|
#
|
8
10
|
|
9
11
|
# Libs
|
10
|
-
require
|
11
|
-
require
|
12
|
+
require 'ffi'
|
13
|
+
require 'forwardable'
|
12
14
|
|
13
15
|
# Modules
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
16
|
+
require 'coremidi/api'
|
17
|
+
require 'coremidi/endpoint'
|
18
|
+
require 'coremidi/type_conversion'
|
17
19
|
|
18
20
|
# Classes
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
21
|
+
require 'coremidi/entity'
|
22
|
+
require 'coremidi/device'
|
23
|
+
require 'coremidi/source'
|
24
|
+
require 'coremidi/destination'
|
23
25
|
|
24
26
|
module CoreMIDI
|
25
|
-
VERSION =
|
27
|
+
VERSION = '0.5.0'
|
26
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
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: []
|
data/test/helper.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
dir = File.dirname(File.expand_path(__FILE__))
|
2
|
-
$LOAD_PATH.unshift dir + "/../lib"
|
3
|
-
|
4
|
-
require "minitest/autorun"
|
5
|
-
require "mocha/test_unit"
|
6
|
-
require "shoulda-context"
|
7
|
-
|
8
|
-
require "coremidi"
|
9
|
-
|
10
|
-
module TestHelper
|
11
|
-
|
12
|
-
extend self
|
13
|
-
|
14
|
-
def device
|
15
|
-
@device ||= select_devices
|
16
|
-
end
|
17
|
-
|
18
|
-
def select_devices
|
19
|
-
@device ||= {}
|
20
|
-
{ :input => CoreMIDI::Source.all, :output => CoreMIDI::Destination.all }.each do |type, devs|
|
21
|
-
puts ""
|
22
|
-
puts "select an #{type.to_s}..."
|
23
|
-
while @device[type].nil?
|
24
|
-
devs.each do |device|
|
25
|
-
puts "#{device.id}: #{device.name}"
|
26
|
-
end
|
27
|
-
selection = $stdin.gets.chomp
|
28
|
-
if selection != ""
|
29
|
-
selection = selection.to_i
|
30
|
-
@device[type] = devs.find { |d| d.id == selection }
|
31
|
-
puts "selected #{selection} for #{type.to_s}" unless @device[type]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
@device
|
36
|
-
end
|
37
|
-
|
38
|
-
def bytestrs_to_ints(arr)
|
39
|
-
data = arr.map { |m| m[:data] }.join
|
40
|
-
output = []
|
41
|
-
until (bytestr = data.slice!(0,2)).eql?("")
|
42
|
-
output << bytestr.hex
|
43
|
-
end
|
44
|
-
output
|
45
|
-
end
|
46
|
-
|
47
|
-
# some MIDI messages
|
48
|
-
VariousMIDIMessages = [
|
49
|
-
[0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7], # SysEx
|
50
|
-
[0x90, 100, 100], # note on
|
51
|
-
[0x90, 43, 100], # note on
|
52
|
-
[0x90, 76, 100], # note on
|
53
|
-
[0x90, 60, 100], # note on
|
54
|
-
[0x80, 100, 100] # note off
|
55
|
-
]
|
56
|
-
|
57
|
-
# some MIDI messages
|
58
|
-
VariousMIDIByteStrMessages = [
|
59
|
-
"F04110421240007F0041F7", # SysEx
|
60
|
-
"906440", # note on
|
61
|
-
"804340" # note off
|
62
|
-
]
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
TestHelper.select_devices
|
data/test/input_buffer_test.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require "helper"
|
2
|
-
|
3
|
-
class InputBufferTest < Minitest::Test
|
4
|
-
|
5
|
-
context "CoreMIDI" do
|
6
|
-
|
7
|
-
setup do
|
8
|
-
sleep(1)
|
9
|
-
end
|
10
|
-
|
11
|
-
context "Source#buffer" do
|
12
|
-
|
13
|
-
setup do
|
14
|
-
@messages = TestHelper::VariousMIDIMessages
|
15
|
-
@messages_arr = @messages.inject { |a,b| a+b }.flatten
|
16
|
-
@received_arr = []
|
17
|
-
@pointer = 0
|
18
|
-
|
19
|
-
@output = TestHelper.device[:output].open
|
20
|
-
@input = TestHelper.device[:input].open
|
21
|
-
@input.buffer.clear
|
22
|
-
end
|
23
|
-
|
24
|
-
should "have the correct messages in the buffer" do
|
25
|
-
bytes = []
|
26
|
-
@messages.each do |message|
|
27
|
-
puts "sending: #{message.inspect}"
|
28
|
-
@output.puts(message)
|
29
|
-
bytes += message
|
30
|
-
|
31
|
-
sleep(0.5)
|
32
|
-
|
33
|
-
buffer = @input.buffer.map { |m| m[:data] }.flatten
|
34
|
-
puts "received: #{buffer.to_s}"
|
35
|
-
assert_equal(bytes, buffer)
|
36
|
-
end
|
37
|
-
assert_equal(bytes.length, @input.buffer.map { |m| m[:data] }.flatten.length)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
data/test/io_test.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require "helper"
|
2
|
-
|
3
|
-
class CoreMIDI::IOTest < Minitest::Test
|
4
|
-
|
5
|
-
# ** these tests assume that TestOutput is connected to TestInput
|
6
|
-
context "CoreMIDI" do
|
7
|
-
|
8
|
-
setup do
|
9
|
-
sleep(1)
|
10
|
-
end
|
11
|
-
|
12
|
-
context "full IO" do
|
13
|
-
|
14
|
-
context "using Arrays" do
|
15
|
-
|
16
|
-
setup do
|
17
|
-
@messages = TestHelper::VariousMIDIMessages
|
18
|
-
@messages_arr = @messages.inject { |a,b| a+b }.flatten
|
19
|
-
@received_arr = []
|
20
|
-
@pointer = 0
|
21
|
-
end
|
22
|
-
|
23
|
-
should "do IO" do
|
24
|
-
TestHelper.device[:output].open do |output|
|
25
|
-
TestHelper.device[:input].open do |input|
|
26
|
-
|
27
|
-
input.buffer.clear
|
28
|
-
|
29
|
-
@messages.each do |msg|
|
30
|
-
|
31
|
-
$>.puts "sending: " + msg.inspect
|
32
|
-
|
33
|
-
output.puts(msg)
|
34
|
-
sleep(1)
|
35
|
-
received = input.gets.map { |m| m[:data] }.flatten
|
36
|
-
|
37
|
-
$>.puts "received: " + received.inspect
|
38
|
-
|
39
|
-
assert_equal(@messages_arr.slice(@pointer, received.length), received)
|
40
|
-
@pointer += received.length
|
41
|
-
@received_arr += received
|
42
|
-
end
|
43
|
-
assert_equal(@messages_arr.length, @received_arr.length)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "using byte Strings" do
|
51
|
-
|
52
|
-
setup do
|
53
|
-
@messages = TestHelper::VariousMIDIByteStrMessages
|
54
|
-
@messages_str = @messages.join
|
55
|
-
@received_str = ""
|
56
|
-
@pointer = 0
|
57
|
-
end
|
58
|
-
|
59
|
-
should "do IO" do
|
60
|
-
TestHelper.device[:output].open do |output|
|
61
|
-
TestHelper.device[:input].open do |input|
|
62
|
-
|
63
|
-
@messages.each do |msg|
|
64
|
-
|
65
|
-
$>.puts "sending: " + msg.inspect
|
66
|
-
|
67
|
-
output.puts(msg)
|
68
|
-
sleep(1)
|
69
|
-
received = input.gets_bytestr.map { |m| m[:data] }.flatten.join
|
70
|
-
$>.puts "received: " + received.inspect
|
71
|
-
|
72
|
-
assert_equal(@messages_str.slice(@pointer, received.length), received)
|
73
|
-
@pointer += received.length
|
74
|
-
@received_str += received
|
75
|
-
end
|
76
|
-
assert_equal(@messages_str, @received_str)
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|