ffi-coremidi 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c86ac17739ef22c4478c0b6074602c35e6797d7
4
- data.tar.gz: 612c5638da885ab668b64952087d52d49112fbdc
3
+ metadata.gz: 4191e1b978dd6f7b928a1c1822850ded9034c0ae
4
+ data.tar.gz: 780525a088dde5901dd1c9326d483ebe356e9c59
5
5
  SHA512:
6
- metadata.gz: dad0821c9b3019da6993960a098d0275a79d009535e09a8e63509908542c3a29b888cfc739cf06b2933e775f8575150c0092d63af9400812c7c0c46dc7db07b0
7
- data.tar.gz: 379c75695cea32e8f7ff3347bc6556eb1ead7301781d0ad845261ccf9630b00d39bf006dc5f4294a3193ebdb6a334cb5f0e27fe93c2636864a5a48d277250c9b
6
+ metadata.gz: 87ca289e7f5edb44619c6503c611828ad60c937e48952c0c99eb65665c75f869079cb1313cf25794fe47db0c944cd8849b764dada1e5c3df1ee82ff448ac9299
7
+ data.tar.gz: 9c48b781b0b7ab4df324ec15c8f3d18c2131d4776849fcd98c75233d5f59297074a7485b2ef47c3d3d551d3886aa706a18586c87822f5b0556f38864e72270cf
@@ -1,12 +1,13 @@
1
1
  module CoreMIDI
2
2
 
3
3
  # Coremidi C binding
4
- module Map
4
+ module API
5
5
 
6
6
  extend FFI::Library
7
7
  ffi_lib '/System/Library/Frameworks/CoreMIDI.framework/Versions/Current/CoreMIDI'
8
8
 
9
- SnowLeopard = `uname -r`.scan(/\d*\.\d*/).first.to_f >= 10.6
9
+ # if osx is 10.6 or higher, there are some differences with 32 vs 64 bit handling
10
+ X86_64 = `uname -r`.scan(/\d*\.\d*/).first.to_f >= 10.6
10
11
 
11
12
  typedef :pointer, :CFStringRef
12
13
  typedef :int32, :ItemCount
@@ -46,41 +47,118 @@ module CoreMIDI
46
47
 
47
48
  end
48
49
 
50
+ def self.get_callback(*args, &block)
51
+ FFI::Function.new(:void, *args, &block)
52
+ end
53
+
54
+ # Pack the given data into a coremidi MIDI packet (used by Destination)
55
+ def self.get_midi_packet(data)
56
+ format = "C" * data.size
57
+ packed_data = data.pack(format)
58
+ char_size = FFI.type_size(:char) * data.size
59
+ bytes = FFI::MemoryPointer.new(char_size)
60
+ bytes.write_string(packed_data)
61
+ bytes
62
+ end
63
+
64
+ def self.create_midi_client(resource_id, name)
65
+ client_name = API::CF.CFStringCreateWithCString(nil, "Client #{resource_id} #{name}", 0)
66
+ client_pointer = FFI::MemoryPointer.new(:pointer)
67
+ error = API.MIDIClientCreate(client_name, nil, nil, client_pointer)
68
+ client = client_pointer.read_pointer
69
+ {
70
+ :error => error,
71
+ :resource => client
72
+ }
73
+ end
74
+
75
+ def self.create_midi_input_port(client, resource_id, name, callback)
76
+ port_name = API::CF.CFStringCreateWithCString(nil, "Port #{resource_id}: #{name}", 0)
77
+ handle_ptr = FFI::MemoryPointer.new(:pointer)
78
+ error = API.MIDIInputPortCreate(client, port_name, callback, nil, handle_ptr)
79
+ handle = handle_ptr.read_pointer
80
+ {
81
+ :error => error,
82
+ :handle => handle
83
+ }
84
+ end
85
+
86
+ def self.create_midi_output_port(client, resource_id, name)
87
+ port_name = CF.CFStringCreateWithCString(nil, "Port #{resource_id}: #{name}", 0)
88
+ port_pointer = FFI::MemoryPointer.new(:pointer)
89
+ error = API.MIDIOutputPortCreate(client, port_name, port_pointer)
90
+ handle = port_pointer.read_pointer
91
+ {
92
+ :error => error,
93
+ :handle => handle
94
+ }
95
+ end
96
+
97
+ # (used by Destination)
98
+ def self.get_midi_packet_list(bytes, size)
99
+ packet_list = FFI::MemoryPointer.new(256)
100
+ packet_ptr = API.MIDIPacketListInit(packet_list)
101
+ packet_ptr = if X86_64
102
+ API.MIDIPacketListAdd(packet_list, 256, packet_ptr, 0, size, bytes)
103
+ else
104
+ # Pass in two 32-bit 0s for the 64 bit time
105
+ API.MIDIPacketListAdd(packet_list, 256, packet_ptr, 0, 0, size, bytes)
106
+ end
107
+ packet_list
108
+ end
109
+
110
+ # @param [FFI::Pointer] resource A pointer to an underlying struct
111
+ # @param [String, Symbol] name The property name to get
112
+ # @return [Fixnum]
113
+ def self.get_int(resource, name)
114
+ property = API::CF.CFStringCreateWithCString(nil, name.to_s, 0)
115
+ value = FFI::MemoryPointer.new(:pointer, 32)
116
+ API::MIDIObjectGetIntegerProperty(resource, property, value)
117
+ value.read_int
118
+ end
119
+
49
120
  # @param [FFI::Pointer] resource A pointer to an underlying struct
50
121
  # @param [String, Symbol] name The property name to get
51
122
  # @return [String]
52
123
  def self.get_string(resource, name)
53
- property = Map::CF.CFStringCreateWithCString(nil, name.to_s, 0)
124
+ property = CF.CFStringCreateWithCString(nil, name.to_s, 0)
54
125
  begin
55
126
  pointer = FFI::MemoryPointer.new(:pointer)
56
- Map::MIDIObjectGetStringProperty(resource, property, pointer)
127
+ MIDIObjectGetStringProperty(resource, property, pointer)
57
128
  string = pointer.read_pointer
58
- length = Map::CF.CFStringGetMaximumSizeForEncoding(Map::CF.CFStringGetLength(string), :kCFStringEncodingUTF8)
129
+ length = CF.CFStringGetMaximumSizeForEncoding(CF.CFStringGetLength(string), :kCFStringEncodingUTF8)
59
130
 
60
131
  bytes = FFI::MemoryPointer.new(length + 1)
61
132
 
62
- if Map::CF.CFStringGetCString(string, bytes, length + 1, :kCFStringEncodingUTF8)
133
+ if CF.CFStringGetCString(string, bytes, length + 1, :kCFStringEncodingUTF8)
63
134
  bytes.read_string.force_encoding("utf-8")
64
135
  end
65
136
  ensure
66
- Map::CF.CFRelease(string) unless string.nil? || string.null?
67
- Map::CF.CFRelease(property) unless property.null?
137
+ CF.CFRelease(string) unless string.nil? || string.null?
138
+ CF.CFRelease(property) unless property.null?
68
139
  end
69
140
  end
70
141
 
142
+ # Called when the system has one or more incoming MIDI messages to deliver to your app.
143
+ # typedef void (*MIDIReadProc) (const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
71
144
  callback :MIDIReadProc, [MIDIPacketList.by_ref, :pointer, :pointer], :pointer
72
145
 
146
+ # OSStatus MIDIClientCreate(CFStringRef name, MIDINotifyProc notifyProc, void *notifyRefCon, MIDIClientRef *outClient);
73
147
  attach_function :MIDIClientCreate, [:pointer, :pointer, :pointer, :pointer], :int
74
148
 
149
+ # OSStatus MIDIClientDispose(MIDIClientRef client);
75
150
  attach_function :MIDIClientDispose, [:pointer], :int
76
151
 
77
- # MIDIEntityRef MIDIDeviceGetEntity (MIDIDeviceRef device, ItemCount entityIndex0);
152
+ # MIDIEntityRef MIDIDeviceGetEntity(MIDIDeviceRef device, ItemCount entityIndex0);
78
153
  attach_function :MIDIDeviceGetEntity, [:MIDIDeviceRef, :ItemCount], :MIDIEntityRef
79
154
 
155
+ # MIDIEndpointRef MIDIGetDestination(ItemCount destIndex0);
80
156
  attach_function :MIDIGetNumberOfDestinations, [], :ItemCount
81
157
 
158
+ # ItemCount MIDIGetNumberOfDevices();
82
159
  attach_function :MIDIGetNumberOfDevices, [], :ItemCount
83
160
 
161
+ # MIDIEndpointRef MIDIEntityGetDestination(MIDIEntityRef entity, ItemCount destIndex0);
84
162
  attach_function :MIDIGetDestination, [:int], :pointer
85
163
 
86
164
  #extern OSStatus MIDIEndpointDispose( MIDIEndpointRef endpt );
@@ -98,19 +176,23 @@ module CoreMIDI
98
176
  # MIDIEndpointRef MIDIEntityGetSource (MIDIEntityRef entity, ItemCount sourceIndex0);
99
177
  attach_function :MIDIEntityGetSource, [:MIDIEntityRef, :ItemCount], :MIDIEndpointRef
100
178
 
179
+ # MIDIDeviceRef MIDIGetDevice(ItemCount deviceIndex0);
101
180
  attach_function :MIDIGetDevice, [:ItemCount], :MIDIDeviceRef
102
181
 
103
- # extern OSStatus MIDIInputPortCreate( MIDIClientRef client, CFStringRef portName, MIDIReadProc readProc, void * refCon, MIDIPortRef * outPort );
182
+ # extern OSStatus MIDIInputPortCreate( MIDIClientRef client, CFStringRef portName,
183
+ # MIDIReadProc readProc, void * refCon, MIDIPortRef * outPort );
104
184
  attach_function :MIDIInputPortCreate, [:MIDIClientRef, :CFStringRef, :MIDIReadProc, :pointer, :MIDIPortRef], :OSStatus
105
185
 
106
186
  # extern OSStatus MIDIObjectGetIntegerProperty( MIDIObjectRef obj, CFStringRef propertyID, SInt32 * outValue );
107
187
  attach_function :MIDIObjectGetIntegerProperty, [:MIDIObjectRef, :CFStringRef, :pointer], :OSStatus
188
+
108
189
  # OSStatus MIDIObjectGetStringProperty (MIDIObjectRef obj, CFStringRef propertyID, CFStringRef *str);
109
190
  attach_function :MIDIObjectGetStringProperty, [:MIDIObjectRef, :CFStringRef, :pointer], :OSStatus
110
- \
191
+
111
192
  # extern OSStatus MIDIOutputPortCreate( MIDIClientRef client, CFStringRef portName, MIDIPortRef * outPort );
112
193
  attach_function :MIDIOutputPortCreate, [:MIDIClientRef, :CFStringRef, :pointer], :int
113
194
 
195
+ # (MIDIPacket*) MIDIPacketListInit(MIDIPacketList *pktlist);
114
196
  attach_function :MIDIPacketListInit, [:pointer], :pointer
115
197
 
116
198
  #extern OSStatus MIDIPortConnectSource( MIDIPortRef port, MIDIEndpointRef source, void * connRefCon )
@@ -125,12 +207,15 @@ module CoreMIDI
125
207
  #extern OSStatus MIDISend(MIDIPortRef port,MIDIEndpointRef dest,const MIDIPacketList *pktlist);
126
208
  attach_function :MIDISend, [:MIDIPortRef, :MIDIEndpointRef, :pointer], :int
127
209
 
210
+ #OSStatus MIDISendSysex(MIDISysexSendRequest *request);
128
211
  attach_function :MIDISendSysex, [:pointer], :int
129
212
 
130
- if SnowLeopard
213
+ # extern MIDIPacket * MIDIPacketListAdd( MIDIPacketList * pktlist, ByteCount listSize,
214
+ # MIDIPacket * curPacket, MIDITimeStamp time,
215
+ # ByteCount nData, const Byte * data)
216
+ if X86_64
131
217
  attach_function :MIDIPacketListAdd, [:pointer, :int, :pointer, :int, :int, :pointer], :pointer
132
218
  else
133
- # extern MIDIPacket * MIDIPacketListAdd( MIDIPacketList * pktlist, ByteCount listSize, MIDIPacket * curPacket, MIDITimeStamp time, ByteCount nData, const Byte * data)
134
219
  attach_function :MIDIPacketListAdd, [:pointer, :int, :pointer, :int, :int, :int, :pointer], :pointer
135
220
  end
136
221
 
@@ -148,12 +233,16 @@ module CoreMIDI
148
233
  # CString* CFStringGetCStringPtr(CFString*, encoding)
149
234
  attach_function :CFStringGetCStringPtr, [:pointer, :int], :pointer
150
235
 
236
+ # CFIndex CFStringGetLength(CFStringRef theString);
151
237
  attach_function :CFStringGetLength, [ :CFStringRef ], :CFIndex
152
238
 
239
+ # CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encoding);
153
240
  attach_function :CFStringGetMaximumSizeForEncoding, [ :CFIndex, :CFStringEncoding ], :long
154
241
 
242
+ # Boolean CFStringGetCString(CFStringRef theString, char *buffer, CFIndex bufferSize, CFStringEncoding encoding);
155
243
  attach_function :CFStringGetCString, [ :CFStringRef, :pointer, :CFIndex, :CFStringEncoding ], :bool
156
244
 
245
+ # void CFRelease (CFTypeRef cf);
157
246
  attach_function :CFRelease, [ :pointer ], :void
158
247
 
159
248
  end
@@ -162,6 +251,7 @@ module CoreMIDI
162
251
  extend FFI::Library
163
252
  ffi_lib '/System/Library/Frameworks/CoreAudio.framework/Versions/Current/CoreAudio'
164
253
 
254
+ # UInt64 AudioConvertHostTimeToNanos(UInt64 IO)
165
255
  attach_function :AudioConvertHostTimeToNanos, [:uint64], :uint64
166
256
  end
167
257
 
@@ -38,7 +38,7 @@ module CoreMIDI
38
38
  # @return [Boolean]
39
39
  def puts_bytes(*data)
40
40
  type = sysex?(data) ? :sysex : :small
41
- bytes = pack_data(data)
41
+ bytes = API.get_midi_packet(data)
42
42
  send("puts_#{type.to_s}", bytes, data.size)
43
43
  true
44
44
  end
@@ -99,7 +99,7 @@ module CoreMIDI
99
99
  def connect
100
100
  client_error = enable_client
101
101
  port_error = initialize_port
102
- @resource = Map.MIDIEntityGetDestination( @entity.resource, @resource_id )
102
+ @resource = API.MIDIEntityGetDestination( @entity.resource, @resource_id )
103
103
  !@resource.address.zero? && client_error.zero? && port_error.zero?
104
104
  end
105
105
  alias_method :connect?, :connect
@@ -108,53 +108,34 @@ module CoreMIDI
108
108
 
109
109
  # Output a short MIDI message
110
110
  def puts_small(bytes, size)
111
- packet_list = FFI::MemoryPointer.new(256)
112
- packet_ptr = Map.MIDIPacketListInit(packet_list)
113
- if Map::SnowLeopard
114
- packet_ptr = Map.MIDIPacketListAdd(packet_list, 256, packet_ptr, 0, size, bytes)
115
- else
116
- # Pass in two 32-bit 0s for the 64 bit time
117
- packet_ptr = Map.MIDIPacketListAdd(packet_list, 256, packet_ptr, 0, 0, size, bytes)
118
- end
119
- Map.MIDISend( @handle, @resource, packet_list )
111
+ packet_list = API.get_midi_packet_list(bytes, size)
112
+ API.MIDISend(@handle, @resource, packet_list)
120
113
  true
121
114
  end
122
115
 
123
116
  # Output a System Exclusive MIDI message
124
117
  def puts_sysex(bytes, size)
125
- request = Map::MIDISysexSendRequest.new
118
+ request = API::MIDISysexSendRequest.new
126
119
  request[:destination] = @resource
127
120
  request[:data] = bytes
128
121
  request[:bytes_to_send] = size
129
122
  request[:complete] = 0
130
123
  request[:completion_proc] = SysexCompletionCallback
131
124
  request[:completion_ref_con] = request
132
- Map.MIDISendSysex(request)
125
+ API.MIDISendSysex(request)
133
126
  true
134
127
  end
135
128
 
136
129
  SysexCompletionCallback =
137
- FFI::Function.new(:void, [:pointer]) do |sysex_request_ptr|
130
+ API.get_callback([:pointer]) do |sysex_request_ptr|
138
131
  # this isn't working for some reason. as of now, it's not needed though
139
132
  end
140
133
 
141
134
  # Initialize a coremidi port for this endpoint
142
135
  def initialize_port
143
- port_name = Map::CF.CFStringCreateWithCString(nil, "Port #{@resource_id}: #{name}", 0)
144
- outport_ptr = FFI::MemoryPointer.new(:pointer)
145
- error = Map.MIDIOutputPortCreate(@client, port_name, outport_ptr)
146
- @handle = outport_ptr.read_pointer
147
- error
148
- end
149
-
150
- # Pack the given data into a coremidi MIDI packet
151
- def pack_data(data)
152
- format = "C" * data.size
153
- packed_data = data.pack(format)
154
- char_size = FFI.type_size(:char) * data.size
155
- bytes = FFI::MemoryPointer.new(char_size)
156
- bytes.write_string(packed_data)
157
- bytes
136
+ port = API.create_midi_output_port(@client, @resource_id, @name)
137
+ @handle = port[:handle]
138
+ port[:error]
158
139
  end
159
140
 
160
141
  # Is the given data a MIDI sysex message?
@@ -1,5 +1,10 @@
1
1
  module CoreMIDI
2
2
 
3
+ # A MIDI device may have multiple logically distinct sub-components. For example, one device may
4
+ # encompass a MIDI synthesizer and a pair of MIDI ports, both addressable via a USB port. Each
5
+ # such element of a device is called a MIDI entity.
6
+ #
7
+ # https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
3
8
  class Device
4
9
 
5
10
  attr_reader :entities,
@@ -48,7 +53,7 @@ module CoreMIDI
48
53
  if !populated? || !use_cache
49
54
  @devices = []
50
55
  counter = 0
51
- while !(device_pointer = Map.MIDIGetDevice(counter)).null?
56
+ while !(device_pointer = API.MIDIGetDevice(counter)).null?
52
57
  device = new(counter, device_pointer, :include_offline => include_offline)
53
58
  @devices << device
54
59
  counter += 1
@@ -74,7 +79,7 @@ module CoreMIDI
74
79
 
75
80
  # Populate the device name
76
81
  def populate_name
77
- @name = Map.get_string(@resource, "name")
82
+ @name = API.get_string(@resource, "name")
78
83
  raise RuntimeError.new("Can't get device name") unless @name
79
84
  end
80
85
 
@@ -92,7 +97,7 @@ module CoreMIDI
92
97
  def populate_entities(options = {})
93
98
  include_if_offline = options[:include_offline] || false
94
99
  i = 0
95
- while !(entity_pointer = Map.MIDIDeviceGetEntity(@resource, i)).null?
100
+ while !(entity_pointer = API.MIDIDeviceGetEntity(@resource, i)).null?
96
101
  @entities << Entity.new(entity_pointer, :include_offline => include_if_offline)
97
102
  i += 1
98
103
  end
@@ -1,5 +1,6 @@
1
1
  module CoreMIDI
2
2
 
3
+ # A MIDI source or destination, owned by an entity.
3
4
  module Endpoint
4
5
 
5
6
  extend Forwardable
@@ -14,10 +15,12 @@ module CoreMIDI
14
15
 
15
16
  alias_method :enabled?, :enabled
16
17
 
17
- def initialize(resource_id, entity, options = {}, &block)
18
+ # @param [Fixnum] resource_id
19
+ # @param [Entity] entity
20
+ def initialize(resource_id, entity)
18
21
  @entity = entity
19
22
  @resource_id = resource_id
20
- @type = self.class.name.split('::').last.downcase.to_sym
23
+ @type = get_type
21
24
  @enabled = false
22
25
  end
23
26
 
@@ -46,12 +49,24 @@ module CoreMIDI
46
49
  all_by_type[type].last
47
50
  end
48
51
 
52
+ # All source endpoints
53
+ # @return [Array<Source>]
54
+ def self.sources
55
+ Device.all.map { |d| d.endpoints[:source] }.flatten
56
+ end
57
+
58
+ # All destination endpoints
59
+ # @return [Array<Destination>]
60
+ def self.destinations
61
+ Device.all.map { |d| d.endpoints[:destination] }.flatten
62
+ end
63
+
49
64
  # A Hash of :source and :destination endpoints
50
65
  # @return [Hash]
51
66
  def self.all_by_type
52
67
  {
53
- :source => Device.all.map { |d| d.endpoints[:source] }.flatten,
54
- :destination => Device.all.map { |d| d.endpoints[:destination] }.flatten
68
+ :source => sources,
69
+ :destination => destinations
55
70
  }
56
71
  end
57
72
 
@@ -72,14 +87,18 @@ module CoreMIDI
72
87
  end
73
88
 
74
89
  protected
90
+
91
+ # Constructs the endpoint type (eg source, destination) for easy consumption
92
+ def get_type
93
+ class_name = self.class.name.split('::').last
94
+ class_name.downcase.to_sym
95
+ end
75
96
 
76
97
  # Enables the coremidi MIDI client that will go with this endpoint
77
98
  def enable_client
78
- client_name = Map::CF.CFStringCreateWithCString(nil, "Client #{@resource_id} #{name}", 0)
79
- client_ptr = FFI::MemoryPointer.new(:pointer)
80
- error = Map.MIDIClientCreate(client_name, nil, nil, client_ptr)
81
- @client = client_ptr.read_pointer
82
- error
99
+ client = API.create_midi_client(@resource_id, @name)
100
+ @client = client[:resource]
101
+ client[:error]
83
102
  end
84
103
 
85
104
  end
@@ -1,9 +1,15 @@
1
1
  module CoreMIDI
2
2
 
3
+ # A MIDI entity can have any number of MIDI endpoints, each of which is a source or destination
4
+ # of a 16-channel MIDI stream. By grouping a device's endpoints into entities, the system has
5
+ # enough information for an application to make reasonable default assumptions about how to
6
+ # communicate in a bi-directional manner with each entity, as is necessary in MIDI librarian
7
+ # applications.
8
+ #
9
+ # https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/Reference/reference.html
3
10
  class Entity
4
11
 
5
12
  attr_reader :endpoints,
6
- :is_online,
7
13
  :manufacturer,
8
14
  :model,
9
15
  :name,
@@ -11,13 +17,14 @@ module CoreMIDI
11
17
 
12
18
  # @param [FFI::Pointer] resource A pointer to the underlying entity
13
19
  # @param [Hash] options
14
- def initialize(resource, options = {}, &block)
20
+ # @option options [Boolean] :include_offline Include offline endpoints in the list
21
+ def initialize(resource, options = {})
15
22
  @endpoints = {
16
23
  :source => [],
17
24
  :destination => []
18
25
  }
19
26
  @resource = resource
20
- populate
27
+ populate(options)
21
28
  end
22
29
 
23
30
  # Assign all of this Entity's endpoints an consecutive local id
@@ -25,7 +32,7 @@ module CoreMIDI
25
32
  # @return [Fixnum]
26
33
  def populate_endpoint_ids(starting_id)
27
34
  counter = 0
28
- @endpoints.values.flatten.each do |endpoint|
35
+ @endpoints.values.flatten.each do |endpoint|
29
36
  endpoint.id = counter + starting_id
30
37
  counter += 1
31
38
  end
@@ -35,7 +42,7 @@ module CoreMIDI
35
42
  # Is the entity online?
36
43
  # @return [Boolean]
37
44
  def online?
38
- get_property(:offline, :type => :int) == 0
45
+ get_int(:offline) == 0
39
46
  end
40
47
 
41
48
  private
@@ -64,17 +71,19 @@ module CoreMIDI
64
71
  end
65
72
 
66
73
  # Populate the endpoints for this entity
74
+ # @param [Hash] options
75
+ # @option options [Boolean] :include_offline Include offline endpoints in the list
67
76
  # @return [Fixnum]
68
- def populate_endpoints
69
- @endpoints.keys.map { |type| populate_endpoints_by_type(type) }.reduce(&:+)
77
+ def populate_endpoints(options = {})
78
+ @endpoints.keys.map { |type| populate_endpoints_by_type(type, options) }.reduce(&:+)
70
79
  end
71
80
 
72
81
  # The number of endpoints for this entity
73
82
  # @param [Symbol] type The endpoint type eg :source, :destination
74
83
  def number_of_endpoints(type)
75
84
  case type
76
- when :source then Map.MIDIEntityGetNumberOfSources(@resource)
77
- when :destination then Map.MIDIEntityGetNumberOfDestinations(@resource)
85
+ when :source then API.MIDIEntityGetNumberOfSources(@resource)
86
+ when :destination then API.MIDIEntityGetNumberOfDestinations(@resource)
78
87
  end
79
88
  end
80
89
 
@@ -82,37 +91,24 @@ module CoreMIDI
82
91
  # @param [Symbol, String] name The property name
83
92
  # @return [String, nil]
84
93
  def get_string(name)
85
- Map.get_string(@resource, name)
94
+ API.get_string(@resource, name)
86
95
  end
87
96
 
88
97
  # An Integer property from the underlying entity
89
98
  # @param [Symbol, String] name The property name
90
99
  # @return [Fixnum, nil]
91
100
  def get_int(name)
92
- property = Map::CF.CFStringCreateWithCString(nil, name.to_s, 0)
93
- value = FFI::MemoryPointer.new(:pointer, 32)
94
- Map::MIDIObjectGetIntegerProperty(@resource, property, value)
95
- value.read_int
101
+ API.get_int(@resource, name)
96
102
  end
97
103
 
98
- # A CString or Integer property from the underlying entity
99
- # @param [Symbol, String] name The property name
100
- # @param [Hash] options
101
- # @option options [Symbol] :type The property type eg :int, :string (default :string)
102
- # @return [Fixnum, String, nil]
103
- def get_property(name, options = {})
104
- case options[:type]
105
- when :string, nil then get_string(name)
106
- when :int then get_int(name)
107
- end
108
- end
109
-
110
104
  # Populate the entity properties from the underlying resource
111
- def populate
112
- @manufacturer = get_property(:manufacturer)
113
- @model = get_property(:model)
105
+ # @param [Hash] options
106
+ # @option options [Boolean] :include_offline Include offline endpoints in the list
107
+ def populate(options = {})
108
+ @manufacturer = get_string(:manufacturer)
109
+ @model = get_string(:model)
114
110
  @name = get_name
115
- populate_endpoints
111
+ populate_endpoints(options)
116
112
  end
117
113
 
118
114
  end
@@ -42,7 +42,7 @@ module CoreMIDI
42
42
  def gets_s
43
43
  messages = gets
44
44
  messages.each do |message|
45
- message[:data] = numeric_bytes_to_hex_string(message[:data])
45
+ message[:data] = TypeConversion.numeric_bytes_to_hex_string(message[:data])
46
46
  end
47
47
  messages
48
48
  end
@@ -69,13 +69,13 @@ module CoreMIDI
69
69
  # Close this input
70
70
  # @return [Boolean]
71
71
  def close
72
- #error = Map.MIDIPortDisconnectSource( @handle, @resource )
72
+ #error = API.MIDIPortDisconnectSource( @handle, @resource )
73
73
  #raise "MIDIPortDisconnectSource returned error code #{error}" unless error.zero?
74
- #error = Map.MIDIClientDispose(@handle)
74
+ #error = API.MIDIClientDispose(@handle)
75
75
  #raise "MIDIClientDispose returned error code #{error}" unless error.zero?
76
- #error = Map.MIDIPortDispose(@handle)
76
+ #error = API.MIDIPortDispose(@handle)
77
77
  #raise "MIDIPortDispose returned error code #{error}" unless error.zero?
78
- #error = Map.MIDIEndpointDispose(@resource)
78
+ #error = API.MIDIEndpointDispose(@resource)
79
79
  #raise "MIDIEndpointDispose returned error code #{error}" unless error.zero?
80
80
  if @enabled
81
81
  @enabled = false
@@ -110,8 +110,8 @@ module CoreMIDI
110
110
  def connect
111
111
  enable_client
112
112
  initialize_port
113
- @resource = Map.MIDIEntityGetSource(@entity.resource, @resource_id)
114
- error = Map.MIDIPortConnectSource(@handle, @resource, nil )
113
+ @resource = API.MIDIEntityGetSource(@entity.resource, @resource_id)
114
+ error = API.MIDIPortConnectSource(@handle, @resource, nil )
115
115
  initialize_buffer
116
116
  @sysex_buffer = []
117
117
  @start_time = Time.now.to_f
@@ -169,12 +169,10 @@ module CoreMIDI
169
169
 
170
170
  # Initialize a coremidi port for this endpoint
171
171
  def initialize_port
172
- port_name = Map::CF.CFStringCreateWithCString(nil, "Port #{@resource_id}: #{name}", 0)
173
- handle_ptr = FFI::MemoryPointer.new(:pointer)
174
172
  @callback = get_event_callback
175
- error = Map.MIDIInputPortCreate(@client, port_name, @callback, nil, handle_ptr)
176
- @handle = handle_ptr.read_pointer
177
- raise "MIDIInputPortCreate returned error code #{error}" unless error.zero?
173
+ port = API.create_midi_input_port(@client, @resource_id, @name, @callback)
174
+ @handle = port[:handle]
175
+ raise "MIDIInputPortCreate returned error code #{port[:error]}" unless port[:error].zero?
178
176
  true
179
177
  end
180
178
 
@@ -189,18 +187,6 @@ module CoreMIDI
189
187
  true
190
188
  end
191
189
 
192
- # Convert an array of numeric byes to a hex string (e.g. [0x90, 0x40, 0x40] becomes "904040")
193
- # @param [Array<Fixnum>] bytes
194
- # @return [String]
195
- def numeric_bytes_to_hex_string(bytes)
196
- string_bytes = bytes.map do |byte|
197
- str = byte.to_s(16).upcase
198
- str = "0" + str if byte < 16
199
- str
200
- end
201
- string_bytes.join
202
- end
203
-
204
190
  end
205
191
 
206
192
  end
@@ -0,0 +1,21 @@
1
+ module CoreMIDI
2
+
3
+ # Helper for convertig MIDI data
4
+ module TypeConversion
5
+
6
+ extend self
7
+
8
+ # Convert an array of numeric byes to a hex string (e.g. [0x90, 0x40, 0x40] becomes "904040")
9
+ # @param [Array<Fixnum>] bytes
10
+ # @return [String]
11
+ def numeric_bytes_to_hex_string(bytes)
12
+ string_bytes = bytes.map do |byte|
13
+ str = byte.to_s(16).upcase
14
+ str = "0" + str if byte < 16
15
+ str
16
+ end
17
+ string_bytes.join
18
+ end
19
+
20
+ end
21
+ end
data/lib/coremidi.rb CHANGED
@@ -8,8 +8,9 @@ require "ffi"
8
8
  require "forwardable"
9
9
 
10
10
  # modules
11
+ require "coremidi/api"
11
12
  require "coremidi/endpoint"
12
- require "coremidi/map"
13
+ require "coremidi/type_conversion"
13
14
 
14
15
  # classes
15
16
  require "coremidi/entity"
@@ -18,5 +19,5 @@ require "coremidi/source"
18
19
  require "coremidi/destination"
19
20
 
20
21
  module CoreMIDI
21
- VERSION = "0.2.3"
22
+ VERSION = "0.3.1"
22
23
  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.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Russo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-02 00:00:00.000000000 Z
11
+ date: 2014-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -34,12 +34,13 @@ files:
34
34
  - LICENSE
35
35
  - README.md
36
36
  - lib/coremidi.rb
37
+ - lib/coremidi/api.rb
37
38
  - lib/coremidi/destination.rb
38
39
  - lib/coremidi/device.rb
39
40
  - lib/coremidi/endpoint.rb
40
41
  - lib/coremidi/entity.rb
41
- - lib/coremidi/map.rb
42
42
  - lib/coremidi/source.rb
43
+ - lib/coremidi/type_conversion.rb
43
44
  - test/helper.rb
44
45
  - test/input_buffer_test.rb
45
46
  - test/io_test.rb