ffi-coremidi 0.2.3 → 0.3.1

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
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