ffi-coremidi 0.2.2 → 0.2.3

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: 89758a3263039237eb24cae058898e594f1fd858
4
- data.tar.gz: a57e14a01b6cc31687995806ee0032fd7d957498
3
+ metadata.gz: 4c86ac17739ef22c4478c0b6074602c35e6797d7
4
+ data.tar.gz: 612c5638da885ab668b64952087d52d49112fbdc
5
5
  SHA512:
6
- metadata.gz: b55637a189a1c6cabc55ecf13503c5bc3562de7159b6ee9ebfd3250530d628fb66bd052ae9b026b98bf1e50e3d50397c66b60b1fff9c533b2639fcbd766ceeab
7
- data.tar.gz: d7e2e91d8a2a1e98819d173f45b8795626d64109ecfb99108ecc1a86b39550084bb6c696e87b2b95acdb83ef838701fc667f1294fe1161083b91bb8a6cefc774
6
+ metadata.gz: dad0821c9b3019da6993960a098d0275a79d009535e09a8e63509908542c3a29b888cfc739cf06b2933e775f8575150c0092d63af9400812c7c0c46dc7db07b0
7
+ data.tar.gz: 379c75695cea32e8f7ff3347bc6556eb1ead7301781d0ad845261ccf9630b00d39bf006dc5f4294a3193ebdb6a334cb5f0e27fe93c2636864a5a48d277250c9b
data/README.md CHANGED
@@ -4,15 +4,15 @@
4
4
 
5
5
  This is a Ruby implementation of the [Apple Core MIDI framework API](https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/CACoreMIDIRef/MIDIServices/).
6
6
 
7
- Note that in the interest of allowing people on other platforms to utilize your code, please consider using [UniMIDI](http://github.com/arirusso/unimidi). UniMIDI is a platform independent wrapper which implements this library with a similar API.
7
+ Note that in the interest of allowing people on other platforms to utilize your code, please consider using [UniMIDI](http://github.com/arirusso/unimidi). UniMIDI is a platform independent wrapper which implements this library and has a similar API.
8
8
 
9
9
  ### Features
10
10
 
11
- * Simpler API than Core MIDI
11
+ * Simplified API
12
12
  * Input and output on multiple devices concurrently
13
- * Agnostically handle different MIDI Message types (including SysEx)
13
+ * Generalized handling of different MIDI Message types (including SysEx)
14
14
  * Timestamped input events
15
- * Internally patch MIDI to other programs using IAC
15
+ * Patch MIDI via software to other programs using IAC
16
16
 
17
17
  ### Requirements
18
18
 
@@ -18,5 +18,5 @@ require "coremidi/source"
18
18
  require "coremidi/destination"
19
19
 
20
20
  module CoreMIDI
21
- VERSION = "0.2.2"
21
+ VERSION = "0.2.3"
22
22
  end
@@ -8,74 +8,85 @@ module CoreMIDI
8
8
  attr_reader :entity
9
9
 
10
10
  # Close this output
11
+ # @return [Boolean]
11
12
  def close
12
- @enabled = false
13
+ if @enabled
14
+ @enabled = false
15
+ true
16
+ else
17
+ false
18
+ end
13
19
  end
14
20
 
15
21
  # Send a MIDI message comprised of a String of hex digits
22
+ # @param [String] data A string of hex digits eg "904040"
23
+ # @return [Boolean]
16
24
  def puts_s(data)
17
25
  data = data.dup
18
- output = []
26
+ bytes = []
19
27
  until (str = data.slice!(0,2)).eql?("")
20
- output << str.hex
28
+ bytes << str.hex
21
29
  end
22
-
23
- puts_bytes(*output)
30
+ puts_bytes(*bytes)
31
+ true
24
32
  end
25
33
  alias_method :puts_bytestr, :puts_s
26
34
  alias_method :puts_hex, :puts_s
27
35
 
28
- # Send a MIDI messages comprised of Numeric bytes
36
+ # Send a MIDI message comprised of numeric bytes
37
+ # @param [*Fixnum] data Numeric bytes eg 0x90, 0x40, 0x40
38
+ # @return [Boolean]
29
39
  def puts_bytes(*data)
30
-
31
- format = "C" * data.size
32
- bytes = (FFI::MemoryPointer.new FFI.type_size(:char) * data.size)
33
- bytes.write_string(data.pack(format))
34
-
35
- if data.first.eql?(0xF0) && data.last.eql?(0xF7)
36
- puts_sysex(bytes, data.size)
37
- else
38
- puts_small(bytes, data.size)
39
- end
40
+ type = sysex?(data) ? :sysex : :small
41
+ bytes = pack_data(data)
42
+ send("puts_#{type.to_s}", bytes, data.size)
43
+ true
40
44
  end
41
45
 
42
- # Send a MIDI message of an indeterminant type
43
- def puts(*a)
44
- case a.first
45
- when Array then puts_bytes(*a.first)
46
- when Numeric then puts_bytes(*a)
47
- when String then puts_bytestr(*a)
46
+ # Send a MIDI message of indeterminate type
47
+ # @param [*Array<Fixnum>, *Array<String>, *Fixnum, *String] args
48
+ # @return [Boolean]
49
+ def puts(*args)
50
+ case args.first
51
+ when Array then puts_bytes(*args.first)
52
+ when Fixnum then puts_bytes(*args)
53
+ when String then puts_bytestr(*args)
48
54
  end
49
55
  end
50
56
  alias_method :write, :puts
51
57
 
52
58
  # Enable this device
59
+ # @return [Destination]
53
60
  def enable(options = {}, &block)
54
- @enabled = true
55
- if block_given?
56
- begin
57
- yield(self)
58
- ensure
59
- close
60
- end
61
- else
62
- self
61
+ if !@enabled
62
+ @enabled = true
63
+ if block_given?
64
+ begin
65
+ yield(self)
66
+ ensure
67
+ close
68
+ end
69
+ end
63
70
  end
71
+ self
64
72
  end
65
73
  alias_method :open, :enable
66
74
  alias_method :start, :enable
67
75
 
68
76
  # Shortcut to the first output endpoint available
77
+ # @return [Destination]
69
78
  def self.first
70
79
  Endpoint.first(:destination)
71
80
  end
72
81
 
73
82
  # Shortcut to the last output endpoint available
83
+ # @return [Destination]
74
84
  def self.last
75
85
  Endpoint.last(:destination)
76
86
  end
77
87
 
78
88
  # All output endpoints
89
+ # @return [Array<Destination>]
79
90
  def self.all
80
91
  Endpoint.all_by_type[:destination]
81
92
  end
@@ -84,6 +95,7 @@ module CoreMIDI
84
95
 
85
96
  # Base initialization for this endpoint -- done whether or not the endpoint is enabled to
86
97
  # check whether it is truly available for use
98
+ # @return [Boolean]
87
99
  def connect
88
100
  client_error = enable_client
89
101
  port_error = initialize_port
@@ -105,6 +117,7 @@ module CoreMIDI
105
117
  packet_ptr = Map.MIDIPacketListAdd(packet_list, 256, packet_ptr, 0, 0, size, bytes)
106
118
  end
107
119
  Map.MIDISend( @handle, @resource, packet_list )
120
+ true
108
121
  end
109
122
 
110
123
  # Output a System Exclusive MIDI message
@@ -117,6 +130,7 @@ module CoreMIDI
117
130
  request[:completion_proc] = SysexCompletionCallback
118
131
  request[:completion_ref_con] = request
119
132
  Map.MIDISendSysex(request)
133
+ true
120
134
  end
121
135
 
122
136
  SysexCompletionCallback =
@@ -133,6 +147,21 @@ module CoreMIDI
133
147
  error
134
148
  end
135
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
158
+ end
159
+
160
+ # Is the given data a MIDI sysex message?
161
+ def sysex?(data)
162
+ data.first.eql?(0xF0) && data.last.eql?(0xF7)
163
+ end
164
+
136
165
  end
137
166
 
138
167
  end
@@ -6,21 +6,24 @@ module CoreMIDI
6
6
  :id, # Unique Numeric id
7
7
  :name # Device name from coremidi
8
8
 
9
+ # @param [Fixnum] id The ID for the device
10
+ # @param [Object] device_pointer The underlying device pointer
11
+ # @param [Hash] options
12
+ # @option options [Boolean] :include_offline Whether to include offline entities (default: false)
9
13
  def initialize(id, device_pointer, options = {})
10
- include_if_offline = options.fetch(:include_offline, false)
11
14
  @id = id
12
15
  @resource = device_pointer
13
16
  @entities = []
14
- populate_name
15
- populate_entities(:include_offline => include_if_offline)
17
+ populate(options)
16
18
  end
17
19
 
18
20
  # Endpoints for this device
19
21
  # @return [Array<Endpoint>]
20
22
  def endpoints
21
23
  endpoints = { :source => [], :destination => [] }
22
- endpoints.keys.each do |k|
23
- endpoints[k] += entities.map { |entity| entity.endpoints[k] }.flatten
24
+ endpoints.keys.each do |key|
25
+ endpoint_group = entities.map { |entity| entity.endpoints[key] }.flatten
26
+ endpoints[key] += endpoint_group
24
27
  end
25
28
  endpoints
26
29
  end
@@ -29,9 +32,9 @@ module CoreMIDI
29
32
  # @param [Integer] last_id The highest already used endpoint ID
30
33
  # @return [Integer] The highest used endpoint ID after populating this device's endpoints
31
34
  def populate_endpoint_ids(last_id)
32
- i = 0
33
- entities.each { |entity| i += entity.populate_endpoint_ids(i + last_id) }
34
- i
35
+ id = 0
36
+ entities.each { |entity| id += entity.populate_endpoint_ids(id + last_id) }
37
+ id
35
38
  end
36
39
 
37
40
  # All cached devices
@@ -42,13 +45,13 @@ module CoreMIDI
42
45
  def self.all(options = {})
43
46
  use_cache = options[:cache] || true
44
47
  include_offline = options[:include_offline] || false
45
- if @devices.nil? || @devices.empty? || !use_cache
48
+ if !populated? || !use_cache
46
49
  @devices = []
47
- i = 0
48
- while !(device_pointer = Map.MIDIGetDevice(i)).null?
49
- device = new(i, device_pointer, :include_offline => include_offline)
50
+ counter = 0
51
+ while !(device_pointer = Map.MIDIGetDevice(counter)).null?
52
+ device = new(counter, device_pointer, :include_offline => include_offline)
50
53
  @devices << device
51
- i+=1
54
+ counter += 1
52
55
  end
53
56
  populate_endpoint_ids
54
57
  end
@@ -62,34 +65,30 @@ module CoreMIDI
62
65
  @devices
63
66
  end
64
67
 
68
+ # Has the device list been populated?
69
+ def self.populated?
70
+ !@devices.nil? && !@devices.empty?
71
+ end
72
+
65
73
  private
66
74
 
67
75
  # Populate the device name
68
76
  def populate_name
69
- prop = Map::CF.CFStringCreateWithCString( nil, "name", 0 )
70
-
71
- begin
72
- name_ptr = FFI::MemoryPointer.new(:pointer)
73
- Map::MIDIObjectGetStringProperty(@resource, prop, name_ptr)
74
- name = name_ptr.read_pointer
75
- len = Map::CF.CFStringGetMaximumSizeForEncoding(Map::CF.CFStringGetLength(name), :kCFStringEncodingUTF8)
76
- bytes = FFI::MemoryPointer.new(len + 1)
77
- raise RuntimeError.new("CFStringGetCString") unless Map::CF.CFStringGetCString(name, bytes, len, :kCFStringEncodingUTF8)
78
- @name = bytes.read_string
79
- ensure
80
- Map::CF.CFRelease(name) unless name.nil? || name.null?
81
- Map::CF.CFRelease(prop) unless prop.null?
82
- end
77
+ @name = Map.get_string(@resource, "name")
78
+ raise RuntimeError.new("Can't get device name") unless @name
83
79
  end
84
80
 
85
81
  # All of the endpoints for all devices a consecutive local id
86
82
  def self.populate_endpoint_ids
87
- i = 0
88
- all.each { |device| i += device.populate_endpoint_ids(i) }
83
+ counter = 0
84
+ all.each { |device| counter += device.populate_endpoint_ids(counter) }
85
+ counter
89
86
  end
90
87
 
91
88
  # Populates the entities for this device. These entities are in turn used to gather the endpoints.
92
- #
89
+ # @param [Hash] options
90
+ # @option options [Boolean] :include_offline Whether to include offline entities (default: false)
91
+ # @return [Fixnum] The number of entities populated
93
92
  def populate_entities(options = {})
94
93
  include_if_offline = options[:include_offline] || false
95
94
  i = 0
@@ -97,6 +96,13 @@ module CoreMIDI
97
96
  @entities << Entity.new(entity_pointer, :include_offline => include_if_offline)
98
97
  i += 1
99
98
  end
99
+ i
100
+ end
101
+
102
+ # Populate the instance
103
+ def populate(options = {})
104
+ populate_name
105
+ populate_entities(:include_offline => options[:include_offline])
100
106
  end
101
107
 
102
108
  end
@@ -22,26 +22,32 @@ module CoreMIDI
22
22
  end
23
23
 
24
24
  # Is this endpoint online?
25
+ # @return [Boolean]
25
26
  def online?
26
27
  @entity.online? && connect?
27
28
  end
28
29
 
29
- # Set the id for this endpoint (the id is immutable once its set)
30
- def id=(val)
31
- @id ||= val
30
+ # Set the id for this endpoint (the id is immutable)
31
+ # @param [Fixnum] val
32
+ # @return [Fixnum]
33
+ def id=(id)
34
+ @id ||= id
32
35
  end
33
36
 
34
37
  # Select the first endpoint of the specified type
38
+ # @return [Destination, Source]
35
39
  def self.first(type)
36
40
  all_by_type[type].first
37
41
  end
38
42
 
39
43
  # Select the last endpoint of the specified type
44
+ # @return [Destination, Source]
40
45
  def self.last(type)
41
46
  all_by_type[type].last
42
47
  end
43
48
 
44
49
  # A Hash of :source and :destination endpoints
50
+ # @return [Hash]
45
51
  def self.all_by_type
46
52
  {
47
53
  :source => Device.all.map { |d| d.endpoints[:source] }.flatten,
@@ -50,15 +56,26 @@ module CoreMIDI
50
56
  end
51
57
 
52
58
  # All endpoints of both types
59
+ # @return [Array<Destination, Source>]
53
60
  def self.all
54
- Device.all.map { |d| d.endpoints }.flatten
61
+ Device.all.map(&:endpoints).flatten
62
+ end
63
+
64
+ # Get the class for the given endpoint type name
65
+ # @param [Symbol] type The endpoint type eg :source, :destination
66
+ # @return [Class] eg Source, Destination
67
+ def self.get_class(type)
68
+ case type
69
+ when :source then Source
70
+ when :destination then Destination
71
+ end
55
72
  end
56
73
 
57
74
  protected
58
75
 
59
76
  # Enables the coremidi MIDI client that will go with this endpoint
60
77
  def enable_client
61
- client_name = Map::CF.CFStringCreateWithCString( nil, "Client #{@resource_id} #{name}", 0 )
78
+ client_name = Map::CF.CFStringCreateWithCString(nil, "Client #{@resource_id} #{name}", 0)
62
79
  client_ptr = FFI::MemoryPointer.new(:pointer)
63
80
  error = Map.MIDIClientCreate(client_name, nil, nil, client_ptr)
64
81
  @client = client_ptr.read_pointer
@@ -9,46 +9,68 @@ module CoreMIDI
9
9
  :name,
10
10
  :resource
11
11
 
12
- alias_method :online?, :is_online
13
-
12
+ # @param [FFI::Pointer] resource A pointer to the underlying entity
13
+ # @param [Hash] options
14
14
  def initialize(resource, options = {}, &block)
15
- @endpoints = { :source => [], :destination => [] }
15
+ @endpoints = {
16
+ :source => [],
17
+ :destination => []
18
+ }
16
19
  @resource = resource
17
- @manufacturer = get_property(:manufacturer)
18
- @model = get_property(:model)
19
- @name = "#{@manufacturer} #{@model}"
20
- @is_online = get_property(:offline, :type => :int) == 0
21
- @endpoints.keys.each { |type| populate_endpoints(type) }
20
+ populate
22
21
  end
23
22
 
24
23
  # Assign all of this Entity's endpoints an consecutive local id
24
+ # @param [Fixnum] starting_id
25
+ # @return [Fixnum]
25
26
  def populate_endpoint_ids(starting_id)
26
- i = 0
27
- @endpoints.values.flatten.each do |e|
28
- e.id = (i + starting_id)
29
- i += 1
27
+ counter = 0
28
+ @endpoints.values.flatten.each do |endpoint|
29
+ endpoint.id = counter + starting_id
30
+ counter += 1
30
31
  end
31
- i
32
+ counter
32
33
  end
33
34
 
35
+ # Is the entity online?
36
+ # @return [Boolean]
37
+ def online?
38
+ get_property(:offline, :type => :int) == 0
39
+ end
40
+
34
41
  private
42
+
43
+ # Construct a display name for the entity
44
+ # @return [String]
45
+ def get_name
46
+ "#{@manufacturer} #{@model}"
47
+ end
35
48
 
36
49
  # Populate endpoints of a specified type for this entity
37
- def populate_endpoints(type, options = {})
38
- include_if_offline = options[:include_offline] || false
39
- endpoint_class = case type
40
- when :source then Source
41
- when :destination then Destination
42
- end
50
+ # @param [Symbol] type The endpoint type eg :source, :destination
51
+ # @param [Hash] options
52
+ # @option options [Boolean] :include_offline Include offline endpoints in the list
53
+ # @return [Fixnum]
54
+ def populate_endpoints_by_type(type, options = {})
55
+ endpoint_class = Endpoint.get_class(type)
43
56
  num_endpoints = number_of_endpoints(type)
44
57
  (0..num_endpoints).each do |i|
45
- ep = endpoint_class.new(i, self)
46
- @endpoints[type] << ep if ep.online? || include_if_offline
58
+ endpoint = endpoint_class.new(i, self)
59
+ if endpoint.online? || options[:include_offline]
60
+ @endpoints[type] << endpoint
61
+ end
47
62
  end
48
63
  @endpoints[type].size
49
64
  end
65
+
66
+ # Populate the endpoints for this entity
67
+ # @return [Fixnum]
68
+ def populate_endpoints
69
+ @endpoints.keys.map { |type| populate_endpoints_by_type(type) }.reduce(&:+)
70
+ end
50
71
 
51
72
  # The number of endpoints for this entity
73
+ # @param [Symbol] type The endpoint type eg :source, :destination
52
74
  def number_of_endpoints(type)
53
75
  case type
54
76
  when :source then Map.MIDIEntityGetNumberOfSources(@resource)
@@ -56,33 +78,43 @@ module CoreMIDI
56
78
  end
57
79
  end
58
80
 
59
- # A CFString property
60
- def get_string(name, pointer)
61
- prop = Map::CF.CFStringCreateWithCString( nil, name.to_s, 0 )
62
- val = Map::CF.CFStringCreateWithCString( nil, name.to_s, 0 ) # placeholder
63
- Map::MIDIObjectGetStringProperty(pointer, prop, val)
64
- Map::CF.CFStringGetCStringPtr(val.read_pointer, 0).read_string rescue nil
81
+ # A CFString property from the underlying entity
82
+ # @param [Symbol, String] name The property name
83
+ # @return [String, nil]
84
+ def get_string(name)
85
+ Map.get_string(@resource, name)
65
86
  end
66
87
 
67
- # An Integer property
68
- def get_int(name, pointer)
69
- prop = Map::CF.CFStringCreateWithCString( nil, name.to_s, 0 )
70
- val = FFI::MemoryPointer.new(:pointer, 32)
71
- Map::MIDIObjectGetIntegerProperty(pointer, prop, val)
72
- val.read_int
88
+ # An Integer property from the underlying entity
89
+ # @param [Symbol, String] name The property name
90
+ # @return [Fixnum, nil]
91
+ 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
73
96
  end
74
97
 
75
- # A CString or Integer property from this Endpoint's entity
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]
76
103
  def get_property(name, options = {})
77
- from = options[:from] || @resource
78
- type = options[:type] || :string
79
-
80
- case type
81
- when :string then get_string(name, from)
82
- when :int then get_int(name, from)
104
+ case options[:type]
105
+ when :string, nil then get_string(name)
106
+ when :int then get_int(name)
83
107
  end
84
108
  end
85
109
 
110
+ # Populate the entity properties from the underlying resource
111
+ def populate
112
+ @manufacturer = get_property(:manufacturer)
113
+ @model = get_property(:model)
114
+ @name = get_name
115
+ populate_endpoints
116
+ end
117
+
86
118
  end
87
119
 
88
120
  end
@@ -46,6 +46,28 @@ module CoreMIDI
46
46
 
47
47
  end
48
48
 
49
+ # @param [FFI::Pointer] resource A pointer to an underlying struct
50
+ # @param [String, Symbol] name The property name to get
51
+ # @return [String]
52
+ def self.get_string(resource, name)
53
+ property = Map::CF.CFStringCreateWithCString(nil, name.to_s, 0)
54
+ begin
55
+ pointer = FFI::MemoryPointer.new(:pointer)
56
+ Map::MIDIObjectGetStringProperty(resource, property, pointer)
57
+ string = pointer.read_pointer
58
+ length = Map::CF.CFStringGetMaximumSizeForEncoding(Map::CF.CFStringGetLength(string), :kCFStringEncodingUTF8)
59
+
60
+ bytes = FFI::MemoryPointer.new(length + 1)
61
+
62
+ if Map::CF.CFStringGetCString(string, bytes, length + 1, :kCFStringEncodingUTF8)
63
+ bytes.read_string.force_encoding("utf-8")
64
+ end
65
+ ensure
66
+ Map::CF.CFRelease(string) unless string.nil? || string.null?
67
+ Map::CF.CFRelease(property) unless property.null?
68
+ end
69
+ end
70
+
49
71
  callback :MIDIReadProc, [MIDIPacketList.by_ref, :pointer, :pointer], :pointer
50
72
 
51
73
  attach_function :MIDIClientCreate, [:pointer, :pointer, :pointer, :pointer], :int
@@ -49,23 +49,25 @@ module CoreMIDI
49
49
  alias_method :gets_bytestr, :gets_s
50
50
 
51
51
  # Enable this the input for use; can be passed a block
52
+ # @return [Source]
52
53
  def enable(options = {}, &block)
53
- @enabled = true
54
-
55
- if block_given?
56
- begin
57
- yield(self)
58
- ensure
59
- close
54
+ if !@enabled
55
+ @enabled = true
56
+ if block_given?
57
+ begin
58
+ yield(self)
59
+ ensure
60
+ close
61
+ end
60
62
  end
61
- else
62
- self
63
63
  end
64
+ self
64
65
  end
65
66
  alias_method :open, :enable
66
67
  alias_method :start, :enable
67
68
 
68
69
  # Close this input
70
+ # @return [Boolean]
69
71
  def close
70
72
  #error = Map.MIDIPortDisconnectSource( @handle, @resource )
71
73
  #raise "MIDIPortDisconnectSource returned error code #{error}" unless error.zero?
@@ -75,21 +77,28 @@ module CoreMIDI
75
77
  #raise "MIDIPortDispose returned error code #{error}" unless error.zero?
76
78
  #error = Map.MIDIEndpointDispose(@resource)
77
79
  #raise "MIDIEndpointDispose returned error code #{error}" unless error.zero?
78
- @enabled = false
79
- true
80
+ if @enabled
81
+ @enabled = false
82
+ true
83
+ else
84
+ false
85
+ end
80
86
  end
81
87
 
82
88
  # Shortcut to the first available input endpoint
89
+ # @return [Source]
83
90
  def self.first
84
91
  Endpoint.first(:source)
85
92
  end
86
93
 
87
94
  # Shortcut to the last available input endpoint
95
+ # @return [Source]
88
96
  def self.last
89
97
  Endpoint.last(:source)
90
98
  end
91
99
 
92
100
  # All input endpoints
101
+ # @return [Array<Source>]
93
102
  def self.all
94
103
  Endpoint.all_by_type[:source]
95
104
  end
@@ -181,6 +190,8 @@ module CoreMIDI
181
190
  end
182
191
 
183
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]
184
195
  def numeric_bytes_to_hex_string(bytes)
185
196
  string_bytes = bytes.map do |byte|
186
197
  str = byte.to_s(16).upcase
@@ -2,42 +2,41 @@ require "helper"
2
2
 
3
3
  class InputBufferTest < Test::Unit::TestCase
4
4
 
5
- include CoreMIDI
6
- include TestHelper
5
+ context "CoreMIDI" do
7
6
 
8
- def test_input_buffer
9
- sleep(1)
7
+ setup do
8
+ sleep(1)
9
+ end
10
10
 
11
- messages = VariousMIDIMessages
12
- bytes = []
11
+ context "Source#buffer" do
13
12
 
14
- $test_device[:output].open do |output|
15
- $test_device[:input].open do |input|
16
-
17
- input.buffer.clear
13
+ setup do
14
+ @messages = TestHelper::VariousMIDIMessages
15
+ @messages_arr = @messages.inject { |a,b| a+b }.flatten
16
+ @received_arr = []
17
+ @pointer = 0
18
18
 
19
- messages.each do |msg|
19
+ @output = $test_device[:output].open
20
+ @input = $test_device[:input].open
21
+ @input.buffer.clear
22
+ end
20
23
 
21
- $>.puts "sending: " + msg.inspect
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
22
30
 
23
- output.puts(msg)
24
-
25
- bytes += msg
26
-
27
31
  sleep(0.5)
28
-
29
- buffer = input.buffer.map { |m| m[:data] }.flatten
30
32
 
31
- $>.puts "received: " + buffer.to_s
32
-
33
+ buffer = @input.buffer.map { |m| m[:data] }.flatten
34
+ puts "received: #{buffer.to_s}"
33
35
  assert_equal(bytes, buffer)
34
-
35
36
  end
36
-
37
- assert_equal(bytes.length, input.buffer.map { |m| m[:data] }.flatten.length)
38
-
37
+ assert_equal(bytes.length, @input.buffer.map { |m| m[:data] }.flatten.length)
39
38
  end
40
39
  end
41
- end
42
40
 
41
+ end
43
42
  end
@@ -1,4 +1,4 @@
1
- require 'helper'
1
+ require "helper"
2
2
 
3
3
  class CoreMIDI::IOTest < Test::Unit::TestCase
4
4
 
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.2
4
+ version: 0.2.3
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-08-31 00:00:00.000000000 Z
11
+ date: 2014-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi