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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 24583f1bb64dea16e2988a4ed7f4c51411000413
4
- data.tar.gz: 3d7804e408e78313e46095ca9fa879c1c427d9e0
2
+ SHA256:
3
+ metadata.gz: d05cb8f763c856b651e7fa5f94499350bc7576cd210e7402ce26bc9bbd714739
4
+ data.tar.gz: 77a98c6abc53d0287bc4e57d7f3cce217da9e32d73fd6a3205602f0c6bd69fbe
5
5
  SHA512:
6
- metadata.gz: c8d2c2fc9c502f21710213e46ecd03937a61f58f0f6bdbc74652ab3995c5615eb1ef23ebdf79a1fe0afaa8fecdd39898ae1ad29b257de5314b2a038f2ff6f688
7
- data.tar.gz: adbb7aa16fe70b8306cd0dd8f9740a15b1b23fd3c4b04ec61616120b3fcc3ad0e1e132c4a526d0cc682d0eb94067940c86f023654e457e01cc7e414033df57aa
6
+ metadata.gz: fc172a0d02c6fc6efd3d1337623e92fdf9bb4b01e08debe2105ed78bb306d49db44308d72cc0041cd04ee04ecb50f4ebda935610bcf18dab67afb2b90e1a5d9b
7
+ data.tar.gz: bbdcf6d8e87f2896db09859e79b6d8c39f33ea2046a10704d917439d7974e50224ed842414ece048e99d671943da7939e47cef74ae3e4683ee4ccdf54646687b
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2011-2017 Ari Russo
1
+ Copyright 2011-2022 Ari Russo
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -48,4 +48,4 @@ Also thank you to [Jeremy Voorhis](http://github.com/jvoorhis) for some useful d
48
48
 
49
49
  Apache 2.0, See the file LICENSE
50
50
 
51
- Copyright (c) 2011-2017 [Ari Russo](http://github.com/arirusso)
51
+ Copyright (c) 2011-2022 [Ari Russo](http://github.com/arirusso)
data/lib/coremidi/api.rb CHANGED
@@ -1,8 +1,8 @@
1
- module CoreMIDI
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 = "C" * data.size
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
- :error => error,
71
- :resource => client
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
- :error => error,
82
- :handle => handle
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
- :error => error,
93
- :handle => handle
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
- API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time, size, bytes)
104
- else
105
- # Pass in two 32-bit 0s for the 64 bit time
106
- time1 = API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time >> 32, time & 0xFFFFFFFF, size, bytes)
107
- end
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("utf-8")
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, [:pointer, :pointer, :pointer, :pointer], :int
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, [:MIDIDeviceRef, :ItemCount], :MIDIEntityRef
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, [:MIDIEntityRef, :int], :MIDIEndpointRef
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, [:MIDIEntityRef, :ItemCount], :MIDIEndpointRef
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, [:MIDIClientRef, :CFStringRef, :MIDIReadProc, :pointer, :MIDIPortRef], :OSStatus
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, [:MIDIObjectRef, :CFStringRef, :pointer], :OSStatus
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, [:MIDIObjectRef, :CFStringRef, :pointer], :OSStatus
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, [:MIDIClientRef, :CFStringRef, :pointer], :int
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, [:MIDIPortRef, :MIDIEndpointRef, :pointer], :OSStatus
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, [:MIDIPortRef, :MIDIEndpointRef], :OSStatus
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, [:MIDIPortRef, :MIDIEndpointRef, :pointer], :int
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, [:pointer, :int, :pointer, :uint64, :int, :pointer], :pointer
216
+ attach_function :MIDIPacketListAdd, %i[pointer int pointer uint64 int pointer], :pointer
219
217
  else
220
- attach_function :MIDIPacketListAdd, [:pointer, :int, :pointer, :int, :int, :int, :pointer], :pointer
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, [ :kCFStringEncodingUTF8, 0x08000100 ]
227
+ enum :CFStringEncoding, [:kCFStringEncodingUTF8, 0x08000100]
231
228
 
232
229
  # CFString* CFStringCreateWithCString( ?, CString, encoding)
233
- attach_function :CFStringCreateWithCString, [:pointer, :string, :int], :pointer
230
+ attach_function :CFStringCreateWithCString, %i[pointer string int], :pointer
234
231
  # CString* CFStringGetCStringPtr(CFString*, encoding)
235
- attach_function :CFStringGetCStringPtr, [:pointer, :int], :pointer
232
+ attach_function :CFStringGetCStringPtr, %i[pointer int], :pointer
236
233
 
237
234
  # CFIndex CFStringGetLength(CFStringRef theString);
238
- attach_function :CFStringGetLength, [ :CFStringRef ], :CFIndex
235
+ attach_function :CFStringGetLength, [:CFStringRef], :CFIndex
239
236
 
240
237
  # CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encoding);
241
- attach_function :CFStringGetMaximumSizeForEncoding, [ :CFIndex, :CFStringEncoding ], :long
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, [ :CFStringRef, :pointer, :CFIndex, :CFStringEncoding ], :bool
241
+ attach_function :CFStringGetCString, %i[CFStringRef pointer CFIndex CFStringEncoding], :bool
245
242
 
246
243
  # void CFRelease (CFTypeRef cf);
247
- attach_function :CFRelease, [ :pointer ], :void
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
@@ -1,8 +1,8 @@
1
- module CoreMIDI
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
- alias_method :puts_bytestr, :puts_s
34
- alias_method :puts_hex, :puts_s
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.to_s}", bytes, data.size)
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
- alias_method :write, :puts
56
+ alias write puts
57
57
 
58
58
  # Enable this device
59
59
  # @return [Destination]
60
- def enable(options = {}, &block)
61
- @enabled = true unless @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
- alias_method :open, :enable
72
- alias_method :start, :enable
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( @entity.resource, @resource_id )
100
+ @resource = API.MIDIEntityGetDestination(@entity.resource, @resource_id)
101
101
  !@resource.address.zero? && client_error.zero? && port_error.zero?
102
102
  end
103
- alias_method :connect?, :connect
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
- # this isn't working for some reason. as of now, it's not needed though
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
@@ -1,12 +1,12 @@
1
- module CoreMIDI
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 = { :source => [], :destination => [] }
29
- endpoints.keys.each do |key|
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
- while !(device_pointer = API.MIDIGetDevice(counter)).null?
57
- device = new(counter, device_pointer, :include_offline => include_offline)
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, "name")
83
- raise RuntimeError.new("Can't get device name") unless @name
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
- while !(entity_pointer = API.MIDIDeviceGetEntity(@resource, i)).null?
101
- @entities << Entity.new(entity_pointer, :include_offline => include_if_offline)
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(:include_offline => options[:include_offline])
110
+ populate_entities(include_offline: options[:include_offline])
111
111
  end
112
-
113
112
  end
114
-
115
113
  end
@@ -1,10 +1,10 @@
1
- module CoreMIDI
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
- alias_method :enabled?, :enabled
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
@@ -1,5 +1,6 @@
1
- module CoreMIDI
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
- counter = 0
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) == 0
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
- if endpoint.online? || options[:include_offline]
67
- @endpoints[type] << endpoint
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
- when :source then API.MIDIEntityGetNumberOfSources(@resource)
86
- when :destination then API.MIDIEntityGetNumberOfDestinations(@resource)
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
@@ -1,8 +1,8 @@
1
- module CoreMIDI
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
- alias_method :read, :gets
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
- alias_method :gets_bytestr, :gets_s
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(options = {}, &block)
53
- @enabled = true unless @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
- alias_method :open, :enable
64
- alias_method :start, :enable
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
- until @queue.empty?
110
- messages << @queue.pop
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
- alias_method :connect?, :connect
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
- # New MIDI messages from the queue
152
- def queued_messages
153
- @queue.pop
154
- end
162
+ @threads_sync_semaphore.synchronize do
163
+ @threads_waiting.each(&:run)
164
+ @threads_waiting.clear
165
+ end
155
166
 
156
- # Are there new MIDI messages in the queue?
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
- Proc.new do |new_packets, refCon_ptr, connRefCon_ptr|
165
- begin
166
- # p "packets received: #{new_packets[:numPackets]}"
167
- timestamp = Time.now.to_f
168
- messages = get_messages(new_packets)
169
- messages.each do |message|
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 |i|
194
+ (count - 1).times do |_i|
188
195
  length_index = find_next_length_index(data)
189
196
  message_length = data[length_index]
190
- unless message_length.nil?
191
- packet_start_index = length_index + 2
192
- packet_end_index = packet_start_index + message_length
193
- if data.length >= packet_end_index + 1
194
- packet = data.slice!(0..packet_end_index)
195
- message = packet.slice(packet_start_index, message_length)
196
- messages << message
197
- end
198
- end
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
- module CoreMIDI
1
+ # frozen_string_literal: true
2
2
 
3
- # Helper for convertig MIDI data
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" + str if byte < 16
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-2017 Ari Russo
7
+ # (c)2011-2022 Ari Russo
6
8
  # https://github.com/arirusso/ffi-coremidi
7
9
  #
8
10
 
9
11
  # Libs
10
- require "ffi"
11
- require "forwardable"
12
+ require 'ffi'
13
+ require 'forwardable'
12
14
 
13
15
  # Modules
14
- require "coremidi/api"
15
- require "coremidi/endpoint"
16
- require "coremidi/type_conversion"
16
+ require 'coremidi/api'
17
+ require 'coremidi/endpoint'
18
+ require 'coremidi/type_conversion'
17
19
 
18
20
  # Classes
19
- require "coremidi/entity"
20
- require "coremidi/device"
21
- require "coremidi/source"
22
- require "coremidi/destination"
21
+ require 'coremidi/entity'
22
+ require 'coremidi/device'
23
+ require 'coremidi/source'
24
+ require 'coremidi/destination'
23
25
 
24
26
  module CoreMIDI
25
- VERSION = "0.4.1"
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.1
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: 2017-07-06 00:00:00.000000000 Z
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.5'
19
+ version: '5.15'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 5.5.0
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.5'
29
+ version: '5.15'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 5.5.0
32
+ version: 5.15.0
33
33
  - !ruby/object:Gem::Dependency
34
- name: mocha
34
+ name: rake
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.1'
39
+ version: '13.0'
40
40
  - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: 1.1.0
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: '1.1'
49
+ version: '13.0'
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: 1.1.0
52
+ version: 13.0.6
53
53
  - !ruby/object:Gem::Dependency
54
- name: rake
54
+ name: rspec
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '10.4'
59
+ version: '3.11'
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 10.4.2
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: '10.4'
69
+ version: '3.11'
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
- version: 10.4.2
72
+ version: 3.11.0
73
73
  - !ruby/object:Gem::Dependency
74
- name: shoulda-context
74
+ name: rubocop
75
75
  requirement: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - "~>"
78
78
  - !ruby/object:Gem::Version
79
- version: '1.2'
79
+ version: '1.25'
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 1.2.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.2'
89
+ version: '1.25'
90
90
  - - ">="
91
91
  - !ruby/object:Gem::Version
92
- version: 1.2.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.9'
99
+ version: '1.15'
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
- version: 1.9.6
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.9'
109
+ version: '1.15'
110
110
  - - ">="
111
111
  - !ruby/object:Gem::Version
112
- version: 1.9.6
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
- rubyforge_project: ffi-coremidi
153
- rubygems_version: 2.6.12
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
@@ -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