midi-communications-macos 0.6.0 → 0.7.0
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 +4 -4
- data/.version +6 -0
- data/.yardoc/checksums +9 -0
- data/.yardoc/complete +0 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/.yardopts +6 -0
- data/LICENSE +159 -668
- data/README.md +6 -13
- data/doc/MIDICommunicationsMacOS/API/CF.html +124 -0
- data/doc/MIDICommunicationsMacOS/API/HostTime.html +124 -0
- data/doc/MIDICommunicationsMacOS/API/MIDIPacket.html +137 -0
- data/doc/MIDICommunicationsMacOS/API/MIDIPacketList.html +137 -0
- data/doc/MIDICommunicationsMacOS/API/MIDISysexSendRequest.html +137 -0
- data/doc/MIDICommunicationsMacOS/API.html +912 -0
- data/doc/MIDICommunicationsMacOS/Destination.html +1983 -0
- data/doc/MIDICommunicationsMacOS/Device.html +1102 -0
- data/doc/MIDICommunicationsMacOS/Endpoint.html +1665 -0
- data/doc/MIDICommunicationsMacOS/Entity.html +971 -0
- data/doc/MIDICommunicationsMacOS/Source.html +1784 -0
- data/doc/MIDICommunicationsMacOS/TypeConversion.html +393 -0
- data/doc/MIDICommunicationsMacOS.html +214 -0
- data/doc/_index.html +250 -0
- data/doc/class_list.html +54 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +503 -0
- data/doc/file.README.html +275 -0
- data/doc/file_list.html +59 -0
- data/doc/frames.html +22 -0
- data/doc/index.html +275 -0
- data/doc/js/app.js +344 -0
- data/doc/js/full_list.js +242 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +542 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/midi-communications-macos/api.rb +7 -1
- data/lib/midi-communications-macos/destination.rb +86 -20
- data/lib/midi-communications-macos/device.rb +52 -18
- data/lib/midi-communications-macos/endpoint.rb +31 -5
- data/lib/midi-communications-macos/entity.rb +20 -6
- data/lib/midi-communications-macos/source.rb +79 -19
- data/lib/midi-communications-macos/type_conversion.rb +11 -4
- data/lib/midi-communications-macos/version.rb +4 -0
- data/lib/midi-communications-macos.rb +39 -1
- data/midi-communications-macos.gemspec +14 -10
- metadata +84 -4
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
#
|
|
2
|
+
# MIDI output endpoint for sending MIDI messages.
|
|
3
|
+
#
|
|
4
|
+
# A Destination represents a MIDI output that can send messages to
|
|
5
|
+
# external MIDI devices or software. Messages can be sent as numeric
|
|
6
|
+
# bytes, hex strings, or arrays.
|
|
7
|
+
#
|
|
8
|
+
# @example Send a Note On/Off sequence
|
|
9
|
+
# output = MIDICommunicationsMacOS::Destination.first
|
|
10
|
+
# output.open
|
|
11
|
+
# output.puts(0x90, 60, 100) # Note On, middle C, velocity 100
|
|
12
|
+
# sleep(0.5)
|
|
13
|
+
# output.puts(0x80, 60, 0) # Note Off
|
|
14
|
+
#
|
|
15
|
+
# @example Send as hex string
|
|
16
|
+
# output.puts_s("903C64") # Note On
|
|
17
|
+
# output.puts_s("803C00") # Note Off
|
|
18
|
+
#
|
|
19
|
+
# @see Source For receiving MIDI messages
|
|
20
|
+
# @see Endpoint For shared endpoint functionality
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
3
23
|
class Destination
|
|
4
24
|
include Endpoint
|
|
5
25
|
|
|
6
26
|
attr_reader :entity
|
|
7
27
|
|
|
8
|
-
#
|
|
9
|
-
#
|
|
28
|
+
# Closes this output.
|
|
29
|
+
#
|
|
30
|
+
# @return [Boolean] true if closed, false if already closed
|
|
10
31
|
def close
|
|
11
32
|
if @enabled
|
|
12
33
|
@enabled = false
|
|
@@ -16,9 +37,14 @@ module MIDICommunicationsMacOS
|
|
|
16
37
|
end
|
|
17
38
|
end
|
|
18
39
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# @
|
|
40
|
+
# Sends a MIDI message as a hex string.
|
|
41
|
+
#
|
|
42
|
+
# @param data [String] hex string (e.g., "904040" for Note On)
|
|
43
|
+
# @return [Boolean] true on success
|
|
44
|
+
#
|
|
45
|
+
# @example
|
|
46
|
+
# output.puts_s("904060") # Note On
|
|
47
|
+
# output.puts_s("804060") # Note Off
|
|
22
48
|
def puts_s(data)
|
|
23
49
|
data = data.dup
|
|
24
50
|
bytes = []
|
|
@@ -31,9 +57,13 @@ module MIDICommunicationsMacOS
|
|
|
31
57
|
alias puts_bytestr puts_s
|
|
32
58
|
alias puts_hex puts_s
|
|
33
59
|
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# @
|
|
60
|
+
# Sends a MIDI message as numeric bytes.
|
|
61
|
+
#
|
|
62
|
+
# @param data [Integer] numeric bytes (e.g., 0x90, 0x40, 0x40)
|
|
63
|
+
# @return [Boolean] true on success
|
|
64
|
+
#
|
|
65
|
+
# @example
|
|
66
|
+
# output.puts_bytes(0x90, 0x40, 0x40) # Note On
|
|
37
67
|
def puts_bytes(*data)
|
|
38
68
|
type = sysex?(data) ? :sysex : :small
|
|
39
69
|
bytes = API.get_midi_packet(data)
|
|
@@ -41,9 +71,24 @@ module MIDICommunicationsMacOS
|
|
|
41
71
|
true
|
|
42
72
|
end
|
|
43
73
|
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
74
|
+
# Sends a MIDI message in any supported format.
|
|
75
|
+
#
|
|
76
|
+
# Accepts multiple formats:
|
|
77
|
+
# - Numeric bytes: `puts(0x90, 0x40, 0x40)`
|
|
78
|
+
# - Array of bytes: `puts([0x90, 0x40, 0x40])`
|
|
79
|
+
# - Hex string: `puts("904040")`
|
|
80
|
+
#
|
|
81
|
+
# @param args [Array<Integer>, Array<String>, Integer, String] MIDI data
|
|
82
|
+
# @return [Boolean] true on success
|
|
83
|
+
#
|
|
84
|
+
# @example Send as bytes
|
|
85
|
+
# output.puts(0x90, 60, 100)
|
|
86
|
+
#
|
|
87
|
+
# @example Send as array
|
|
88
|
+
# output.puts([0x90, 60, 100])
|
|
89
|
+
#
|
|
90
|
+
# @example Send as hex string
|
|
91
|
+
# output.puts("903C64")
|
|
47
92
|
def puts(*args)
|
|
48
93
|
case args.first
|
|
49
94
|
when Array then args.each { |arg| puts(*arg) }
|
|
@@ -53,8 +98,19 @@ module MIDICommunicationsMacOS
|
|
|
53
98
|
end
|
|
54
99
|
alias write puts
|
|
55
100
|
|
|
56
|
-
#
|
|
57
|
-
#
|
|
101
|
+
# Opens this output for use.
|
|
102
|
+
#
|
|
103
|
+
# When a block is given, the output is automatically closed when
|
|
104
|
+
# the block exits.
|
|
105
|
+
#
|
|
106
|
+
# @yield [destination] optional block to execute with the open output
|
|
107
|
+
# @yieldparam destination [Destination] self
|
|
108
|
+
# @return [Destination] self
|
|
109
|
+
#
|
|
110
|
+
# @example Open with automatic close
|
|
111
|
+
# output.open do |o|
|
|
112
|
+
# o.puts(0x90, 60, 100)
|
|
113
|
+
# end
|
|
58
114
|
def enable
|
|
59
115
|
@enabled ||= true
|
|
60
116
|
if block_given?
|
|
@@ -69,20 +125,30 @@ module MIDICommunicationsMacOS
|
|
|
69
125
|
alias open enable
|
|
70
126
|
alias start enable
|
|
71
127
|
|
|
72
|
-
#
|
|
73
|
-
#
|
|
128
|
+
# Returns the first available output endpoint.
|
|
129
|
+
#
|
|
130
|
+
# @return [Destination] the first destination
|
|
131
|
+
#
|
|
132
|
+
# @example
|
|
133
|
+
# output = MIDICommunicationsMacOS::Destination.first
|
|
74
134
|
def self.first
|
|
75
135
|
Endpoint.first(:destination)
|
|
76
136
|
end
|
|
77
137
|
|
|
78
|
-
#
|
|
79
|
-
#
|
|
138
|
+
# Returns the last available output endpoint.
|
|
139
|
+
#
|
|
140
|
+
# @return [Destination] the last destination
|
|
80
141
|
def self.last
|
|
81
142
|
Endpoint.last(:destination)
|
|
82
143
|
end
|
|
83
144
|
|
|
84
|
-
#
|
|
85
|
-
#
|
|
145
|
+
# Returns all available output endpoints.
|
|
146
|
+
#
|
|
147
|
+
# @return [Array<Destination>] all destinations
|
|
148
|
+
#
|
|
149
|
+
# @example
|
|
150
|
+
# outputs = MIDICommunicationsMacOS::Destination.all
|
|
151
|
+
# outputs.each { |o| puts o.display_name }
|
|
86
152
|
def self.all
|
|
87
153
|
Endpoint.all_by_type[:destination]
|
|
88
154
|
end
|
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
#
|
|
3
|
-
# encompass a MIDI synthesizer and a pair of MIDI ports, both addressable via a USB port. Each
|
|
4
|
-
# such element of a device is called a MIDI entity.
|
|
2
|
+
# Represents a physical or virtual MIDI device.
|
|
5
3
|
#
|
|
6
|
-
#
|
|
4
|
+
# A MIDI device may have multiple logically distinct sub-components. For example,
|
|
5
|
+
# one device may encompass a MIDI synthesizer and a pair of MIDI ports, both
|
|
6
|
+
# addressable via a USB port. Each such element of a device is called an {Entity}.
|
|
7
|
+
#
|
|
8
|
+
# Devices contain {Entity entities}, which in turn contain {Endpoint endpoints}
|
|
9
|
+
# ({Source sources} and {Destination destinations}).
|
|
10
|
+
#
|
|
11
|
+
# @example List all devices
|
|
12
|
+
# MIDICommunicationsMacOS::Device.all.each do |device|
|
|
13
|
+
# puts device.name
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @see https://developer.apple.com/documentation/coremidi/midideviceref
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
7
19
|
class Device
|
|
20
|
+
# @!attribute [r] entities
|
|
21
|
+
# @return [Array<Entity>] the device's entities
|
|
22
|
+
# @!attribute [r] id
|
|
23
|
+
# @return [Integer] unique numeric ID
|
|
24
|
+
# @!attribute [r] name
|
|
25
|
+
# @return [String] device name from Core MIDI
|
|
8
26
|
attr_reader :entities,
|
|
9
|
-
:id,
|
|
10
|
-
:name
|
|
27
|
+
:id,
|
|
28
|
+
:name
|
|
11
29
|
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# @param [
|
|
30
|
+
# Creates a new Device wrapper.
|
|
31
|
+
#
|
|
32
|
+
# @param id [Integer] the device ID
|
|
33
|
+
# @param device_pointer [FFI::Pointer] pointer to the Core MIDI device
|
|
34
|
+
# @param include_offline [Boolean] whether to include offline entities
|
|
35
|
+
# @api private
|
|
15
36
|
def initialize(id, device_pointer, include_offline: false)
|
|
16
37
|
@id = id
|
|
17
38
|
@resource = device_pointer
|
|
@@ -19,8 +40,9 @@ module MIDICommunicationsMacOS
|
|
|
19
40
|
populate(include_offline: include_offline)
|
|
20
41
|
end
|
|
21
42
|
|
|
22
|
-
#
|
|
23
|
-
#
|
|
43
|
+
# Returns all endpoints for this device, grouped by type.
|
|
44
|
+
#
|
|
45
|
+
# @return [Hash{Symbol => Array<Endpoint>}] hash with :source and :destination keys
|
|
24
46
|
def endpoints
|
|
25
47
|
endpoints = { source: [], destination: [] }
|
|
26
48
|
endpoints.each_key do |key|
|
|
@@ -39,11 +61,19 @@ module MIDICommunicationsMacOS
|
|
|
39
61
|
id
|
|
40
62
|
end
|
|
41
63
|
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
64
|
+
# Returns all available MIDI devices.
|
|
65
|
+
#
|
|
66
|
+
# Devices are cached by default. Use `cache: false` to refresh, or call
|
|
67
|
+
# {.refresh} to clear the cache.
|
|
68
|
+
#
|
|
69
|
+
# @param options [Hash] options for device selection
|
|
70
|
+
# @option options [Boolean] :cache (true) whether to use cached devices
|
|
71
|
+
# @option options [Boolean] :include_offline (false) include offline devices
|
|
72
|
+
# @return [Array<Device>] all available devices
|
|
73
|
+
#
|
|
74
|
+
# @example
|
|
75
|
+
# devices = MIDICommunicationsMacOS::Device.all
|
|
76
|
+
# devices.each { |d| puts d.name }
|
|
47
77
|
def self.all(options = {})
|
|
48
78
|
use_cache = options[:cache] || true
|
|
49
79
|
include_offline = options[:include_offline] || false
|
|
@@ -60,8 +90,12 @@ module MIDICommunicationsMacOS
|
|
|
60
90
|
@devices
|
|
61
91
|
end
|
|
62
92
|
|
|
63
|
-
#
|
|
64
|
-
#
|
|
93
|
+
# Clears the device cache.
|
|
94
|
+
#
|
|
95
|
+
# Call this when MIDI devices are plugged in or unplugged while the
|
|
96
|
+
# program is running, then call {.all} to get the updated list.
|
|
97
|
+
#
|
|
98
|
+
# @return [Array<Device>] the cleared cache (empty array)
|
|
65
99
|
def self.refresh
|
|
66
100
|
@devices.clear
|
|
67
101
|
@devices
|
|
@@ -1,18 +1,44 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
# A source or destination of a 16-channel MIDI stream
|
|
2
|
+
# A source or destination of a 16-channel MIDI stream.
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# This module provides shared functionality for both {Source} (input) and
|
|
5
|
+
# {Destination} (output) endpoints. Each endpoint represents a single
|
|
6
|
+
# point of MIDI communication within an {Entity}.
|
|
7
|
+
#
|
|
8
|
+
# @see https://developer.apple.com/documentation/coremidi/midiendpointref
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
5
11
|
module Endpoint
|
|
6
12
|
extend Forwardable
|
|
7
13
|
|
|
8
|
-
|
|
14
|
+
# @!attribute [r] enabled
|
|
15
|
+
# @return [Boolean] whether the endpoint has been initialized
|
|
16
|
+
# @!attribute [r] entity
|
|
17
|
+
# @return [Entity] the parent entity
|
|
18
|
+
# @!attribute [r] id
|
|
19
|
+
# @return [Integer] unique local numeric ID of the endpoint
|
|
20
|
+
# @!attribute [r] resource_id
|
|
21
|
+
# @return [Integer] Core MIDI resource identifier
|
|
22
|
+
# @!attribute [r] type
|
|
23
|
+
# @return [Symbol] endpoint type (:source or :destination)
|
|
24
|
+
attr_reader :enabled,
|
|
9
25
|
:entity,
|
|
10
|
-
:id,
|
|
11
|
-
:resource_id,
|
|
26
|
+
:id,
|
|
27
|
+
:resource_id,
|
|
12
28
|
:type
|
|
13
29
|
|
|
30
|
+
# @!method manufacturer
|
|
31
|
+
# @return [String] device manufacturer name (delegated to entity)
|
|
32
|
+
# @!method model
|
|
33
|
+
# @return [String] device model name (delegated to entity)
|
|
34
|
+
# @!method name
|
|
35
|
+
# @return [String] endpoint name (delegated to entity)
|
|
36
|
+
# @!method display_name
|
|
37
|
+
# @return [String] formatted display name (delegated to entity)
|
|
14
38
|
def_delegators :entity, :manufacturer, :model, :name, :display_name
|
|
15
39
|
|
|
40
|
+
# @!method enabled?
|
|
41
|
+
# @return [Boolean] alias for {#enabled}
|
|
16
42
|
alias enabled? enabled
|
|
17
43
|
|
|
18
44
|
# @param [Integer] resource_id
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
# A
|
|
3
|
-
# of a 16-channel MIDI stream. By grouping a device's endpoints into entities, the system has
|
|
4
|
-
# enough information for an application to make reasonable default assumptions about how to
|
|
5
|
-
# communicate in a bi-directional manner with each entity, as is necessary in MIDI librarian
|
|
6
|
-
# applications.
|
|
2
|
+
# A logical grouping of MIDI endpoints within a device.
|
|
7
3
|
#
|
|
8
|
-
#
|
|
4
|
+
# A MIDI entity can have any number of MIDI endpoints, each of which is a
|
|
5
|
+
# {Source source} or {Destination destination} of a 16-channel MIDI stream.
|
|
6
|
+
# By grouping a device's endpoints into entities, the system has enough
|
|
7
|
+
# information for applications to make reasonable default assumptions about
|
|
8
|
+
# bidirectional communication.
|
|
9
|
+
#
|
|
10
|
+
# @see https://developer.apple.com/documentation/coremidi/midientityref
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
9
13
|
class Entity
|
|
14
|
+
# @!attribute [r] endpoints
|
|
15
|
+
# @return [Hash{Symbol => Array<Endpoint>}] endpoints grouped by :source and :destination
|
|
16
|
+
# @!attribute [r] manufacturer
|
|
17
|
+
# @return [String] device manufacturer name
|
|
18
|
+
# @!attribute [r] model
|
|
19
|
+
# @return [String] device model name
|
|
20
|
+
# @!attribute [r] name
|
|
21
|
+
# @return [String] entity name
|
|
22
|
+
# @!attribute [r] resource
|
|
23
|
+
# @return [FFI::Pointer] pointer to the Core MIDI entity
|
|
10
24
|
attr_reader :endpoints,
|
|
11
25
|
:manufacturer,
|
|
12
26
|
:model,
|
|
@@ -1,8 +1,40 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
#
|
|
2
|
+
# MIDI input endpoint for receiving MIDI messages.
|
|
3
|
+
#
|
|
4
|
+
# A Source represents a MIDI input that can receive messages from
|
|
5
|
+
# external MIDI devices or software. Messages are queued and can
|
|
6
|
+
# be retrieved using {#gets} or {#gets_s}.
|
|
7
|
+
#
|
|
8
|
+
# @example Open and read from the first input
|
|
9
|
+
# input = MIDICommunicationsMacOS::Source.first
|
|
10
|
+
# input.open
|
|
11
|
+
# messages = input.gets
|
|
12
|
+
# # => [{ data: [144, 60, 100], timestamp: 1234567890.123 }]
|
|
13
|
+
#
|
|
14
|
+
# @example Read messages as hex strings
|
|
15
|
+
# messages = input.gets_s
|
|
16
|
+
# # => [{ data: "903C64", timestamp: 1234567890.123 }]
|
|
17
|
+
#
|
|
18
|
+
# @see Destination For sending MIDI messages
|
|
19
|
+
# @see Endpoint For shared endpoint functionality
|
|
20
|
+
#
|
|
21
|
+
# @api public
|
|
3
22
|
class Source
|
|
4
23
|
include Endpoint
|
|
5
24
|
|
|
25
|
+
# Reads MIDI messages from the input buffer.
|
|
26
|
+
#
|
|
27
|
+
# Returns an array of MIDI event hashes. Each hash contains:
|
|
28
|
+
# - `:data` - Array of numeric bytes (e.g., [144, 60, 100])
|
|
29
|
+
# - `:timestamp` - Float timestamp when the message was received
|
|
30
|
+
#
|
|
31
|
+
# This method blocks until at least one message is available.
|
|
32
|
+
#
|
|
33
|
+
# @return [Array<Hash>] array of MIDI event hashes
|
|
34
|
+
#
|
|
35
|
+
# @example
|
|
36
|
+
# messages = input.gets
|
|
37
|
+
# # => [{ data: [144, 60, 100], timestamp: 1024.5 }]
|
|
6
38
|
#
|
|
7
39
|
# An array of MIDI event hashes as such:
|
|
8
40
|
# [
|
|
@@ -20,15 +52,17 @@ module MIDICommunicationsMacOS
|
|
|
20
52
|
end
|
|
21
53
|
alias read gets
|
|
22
54
|
|
|
23
|
-
#
|
|
24
|
-
# digits as such:
|
|
25
|
-
# [
|
|
26
|
-
# { data: "904060", timestamp: 904 },
|
|
27
|
-
# { data: "804060", timestamp: 1150 },
|
|
28
|
-
# { data: "90447F", timestamp: 1300 }
|
|
29
|
-
# ]
|
|
55
|
+
# Reads MIDI messages as hex strings.
|
|
30
56
|
#
|
|
31
|
-
#
|
|
57
|
+
# Same as {#gets} but returns message data as hex strings instead
|
|
58
|
+
# of byte arrays.
|
|
59
|
+
#
|
|
60
|
+
# @return [Array<Hash>] array of MIDI event hashes with hex string data
|
|
61
|
+
#
|
|
62
|
+
# @example
|
|
63
|
+
# messages = input.gets_s
|
|
64
|
+
# # => [{ data: "904060", timestamp: 904 },
|
|
65
|
+
# # { data: "804060", timestamp: 1150 }]
|
|
32
66
|
def gets_s
|
|
33
67
|
messages = gets
|
|
34
68
|
messages.each do |message|
|
|
@@ -38,8 +72,23 @@ module MIDICommunicationsMacOS
|
|
|
38
72
|
end
|
|
39
73
|
alias gets_bytestr gets_s
|
|
40
74
|
|
|
41
|
-
#
|
|
42
|
-
#
|
|
75
|
+
# Opens this input for use.
|
|
76
|
+
#
|
|
77
|
+
# When a block is given, the input is automatically closed when
|
|
78
|
+
# the block exits.
|
|
79
|
+
#
|
|
80
|
+
# @yield [source] optional block to execute with the open input
|
|
81
|
+
# @yieldparam source [Source] self
|
|
82
|
+
# @return [Source] self
|
|
83
|
+
#
|
|
84
|
+
# @example Open with automatic close
|
|
85
|
+
# input.open do |i|
|
|
86
|
+
# messages = i.gets
|
|
87
|
+
# end
|
|
88
|
+
#
|
|
89
|
+
# @example Open manually
|
|
90
|
+
# input.open
|
|
91
|
+
# messages = input.gets
|
|
43
92
|
def enable
|
|
44
93
|
@enabled ||= true
|
|
45
94
|
if block_given?
|
|
@@ -54,8 +103,9 @@ module MIDICommunicationsMacOS
|
|
|
54
103
|
alias open enable
|
|
55
104
|
alias start enable
|
|
56
105
|
|
|
57
|
-
#
|
|
58
|
-
#
|
|
106
|
+
# Closes this input.
|
|
107
|
+
#
|
|
108
|
+
# @return [Boolean] true if closed, false if already closed
|
|
59
109
|
def close
|
|
60
110
|
#error = API.MIDIPortDisconnectSource( @handle, @resource )
|
|
61
111
|
#raise "MIDIPortDisconnectSource returned error code #{error}" unless error.zero?
|
|
@@ -73,20 +123,30 @@ module MIDICommunicationsMacOS
|
|
|
73
123
|
end
|
|
74
124
|
end
|
|
75
125
|
|
|
76
|
-
#
|
|
77
|
-
#
|
|
126
|
+
# Returns the first available input endpoint.
|
|
127
|
+
#
|
|
128
|
+
# @return [Source] the first source
|
|
129
|
+
#
|
|
130
|
+
# @example
|
|
131
|
+
# input = MIDICommunicationsMacOS::Source.first
|
|
78
132
|
def self.first
|
|
79
133
|
Endpoint.first(:source)
|
|
80
134
|
end
|
|
81
135
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
136
|
+
# Returns the last available input endpoint.
|
|
137
|
+
#
|
|
138
|
+
# @return [Source] the last source
|
|
84
139
|
def self.last
|
|
85
140
|
Endpoint.last(:source)
|
|
86
141
|
end
|
|
87
142
|
|
|
88
|
-
#
|
|
89
|
-
#
|
|
143
|
+
# Returns all available input endpoints.
|
|
144
|
+
#
|
|
145
|
+
# @return [Array<Source>] all sources
|
|
146
|
+
#
|
|
147
|
+
# @example
|
|
148
|
+
# inputs = MIDICommunicationsMacOS::Source.all
|
|
149
|
+
# inputs.each { |i| puts i.display_name }
|
|
90
150
|
def self.all
|
|
91
151
|
Endpoint.all_by_type[:source]
|
|
92
152
|
end
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
module MIDICommunicationsMacOS
|
|
2
|
-
#
|
|
2
|
+
# Utility methods for converting between MIDI data formats.
|
|
3
|
+
#
|
|
4
|
+
# @api public
|
|
3
5
|
module TypeConversion
|
|
4
6
|
extend self
|
|
5
7
|
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# @
|
|
8
|
+
# Converts an array of numeric bytes to a hex string.
|
|
9
|
+
#
|
|
10
|
+
# @param bytes [Array<Integer>] array of numeric bytes (e.g., [0x90, 0x40, 0x40])
|
|
11
|
+
# @return [String] uppercase hex string (e.g., "904040")
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# TypeConversion.numeric_bytes_to_hex_string([0x90, 0x40, 0x40])
|
|
15
|
+
# # => "904040"
|
|
9
16
|
def numeric_bytes_to_hex_string(bytes)
|
|
10
17
|
string_bytes = bytes.map do |byte|
|
|
11
18
|
str = byte.to_s(16).upcase
|
|
@@ -21,6 +21,44 @@ require 'midi-communications-macos/device'
|
|
|
21
21
|
require 'midi-communications-macos/source'
|
|
22
22
|
require 'midi-communications-macos/destination'
|
|
23
23
|
|
|
24
|
+
require_relative 'midi-communications-macos/version'
|
|
25
|
+
|
|
26
|
+
# macOS-specific MIDI I/O using the Core MIDI framework.
|
|
27
|
+
#
|
|
28
|
+
# This library provides low-level access to MIDI devices on macOS through
|
|
29
|
+
# Apple's Core MIDI framework via FFI bindings. It is typically used through
|
|
30
|
+
# the higher-level {https://github.com/javier-sy/midi-communications midi-communications} gem.
|
|
31
|
+
#
|
|
32
|
+
# The main classes are:
|
|
33
|
+
# - {Source} - MIDI input endpoints for receiving messages
|
|
34
|
+
# - {Destination} - MIDI output endpoints for sending messages
|
|
35
|
+
# - {Device} - Physical or virtual MIDI devices
|
|
36
|
+
# - {Entity} - Logical groupings of endpoints within a device
|
|
37
|
+
#
|
|
38
|
+
# @example List all MIDI sources (inputs)
|
|
39
|
+
# MIDICommunicationsMacOS::Source.all.each do |source|
|
|
40
|
+
# puts "#{source.id}: #{source.display_name}"
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# @example List all MIDI destinations (outputs)
|
|
44
|
+
# MIDICommunicationsMacOS::Destination.all.each do |dest|
|
|
45
|
+
# puts "#{dest.id}: #{dest.display_name}"
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# @example Send a MIDI message
|
|
49
|
+
# output = MIDICommunicationsMacOS::Destination.first
|
|
50
|
+
# output.open
|
|
51
|
+
# output.puts(0x90, 60, 100) # Note On
|
|
52
|
+
# output.puts(0x80, 60, 0) # Note Off
|
|
53
|
+
#
|
|
54
|
+
# @example Receive MIDI messages
|
|
55
|
+
# input = MIDICommunicationsMacOS::Source.first
|
|
56
|
+
# input.open
|
|
57
|
+
# messages = input.gets
|
|
58
|
+
# # => [{ data: [144, 60, 100], timestamp: 1234567890.123 }]
|
|
59
|
+
#
|
|
60
|
+
# @see https://developer.apple.com/documentation/coremidi Apple Core MIDI Documentation
|
|
61
|
+
#
|
|
62
|
+
# @api public
|
|
24
63
|
module MIDICommunicationsMacOS
|
|
25
|
-
VERSION = '0.5.4'.freeze
|
|
26
64
|
end
|
|
@@ -1,30 +1,34 @@
|
|
|
1
|
+
require_relative 'lib/midi-communications-macos/version'
|
|
2
|
+
|
|
1
3
|
Gem::Specification.new do |s|
|
|
2
4
|
s.name = 'midi-communications-macos'
|
|
3
|
-
s.version =
|
|
5
|
+
s.version = MIDICommunicationsMacOS::VERSION
|
|
4
6
|
s.date = '2025-08-23'
|
|
5
7
|
s.summary = 'Realtime MIDI IO with Ruby for OSX'
|
|
6
8
|
s.description = 'Access the Apple Core MIDI framework API with Ruby.'
|
|
7
9
|
s.authors = ['Javier Sánchez Yeste']
|
|
8
10
|
s.email = ['javier.sy@gmail.com']
|
|
9
11
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
10
|
-
s.homepage = 'https://
|
|
11
|
-
s.license = 'LGPL-3.0'
|
|
12
|
+
s.homepage = 'https://github.com/javier-sy/midi-communications-macos'
|
|
13
|
+
s.license = 'LGPL-3.0-or-later'
|
|
12
14
|
|
|
13
15
|
s.required_ruby_version = '>= 2.7'
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# "changelog_uri" => ""
|
|
21
|
-
#}
|
|
17
|
+
s.metadata = {
|
|
18
|
+
'homepage_uri' => s.homepage,
|
|
19
|
+
'source_code_uri' => s.homepage,
|
|
20
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/midi-communications-macos'
|
|
21
|
+
}
|
|
22
22
|
|
|
23
23
|
s.add_runtime_dependency 'ffi', '~> 1.15', '>= 1.15.4'
|
|
24
24
|
|
|
25
25
|
s.add_development_dependency 'minitest', '~>5', '>= 5.14.4'
|
|
26
26
|
s.add_development_dependency 'rake', '~>13', '>= 13.0.6'
|
|
27
27
|
s.add_development_dependency 'shoulda-context', '~>2', '>= 2.0.0'
|
|
28
|
+
|
|
29
|
+
s.add_development_dependency 'yard', '~> 0.9'
|
|
30
|
+
s.add_development_dependency 'redcarpet', '~> 3.6'
|
|
31
|
+
s.add_development_dependency 'webrick', '~> 1.8'
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
|