ffi-coremidi 0.2.2 → 0.2.3

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