Module: MIDICommunicationsMacOS::API Private

Extended by:
FFI::Library
Defined in:
lib/midi-communications-macos/api.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Low-level FFI bindings to Apple's Core MIDI framework.

This module provides direct access to Core MIDI C functions via FFI. Most users should use the higher-level Source, Destination, and Device classes instead.

Defined Under Namespace

Modules: CF, HostTime Classes: MIDIPacket, MIDIPacketList, MIDISysexSendRequest

Constant Summary collapse

X86_64 =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

if osx is 10.6 or higher, there are some differences with 32 vs 64 bit handling

`uname -r`.scan(/\d*\.\d*/).first.to_f >= 10.6

Class Method Summary collapse

Class Method Details

.create_midi_client(resource_id, name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



68
69
70
71
72
73
74
75
76
77
# File 'lib/midi-communications-macos/api.rb', line 68

def self.create_midi_client(resource_id, name)
  client_name = API::CF.CFStringCreateWithCString(nil, "Client #{resource_id} #{name}", 0)
  client_pointer = FFI::MemoryPointer.new(:pointer)
  error = API.MIDIClientCreate(client_name, nil, nil, client_pointer)
  client = client_pointer.read_pointer
  {
    error: error,
    resource: client
  }
end

.create_midi_input_port(client, resource_id, name, callback) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



79
80
81
82
83
84
85
86
87
88
# File 'lib/midi-communications-macos/api.rb', line 79

def self.create_midi_input_port(client, resource_id, name, callback)
  port_name = API::CF.CFStringCreateWithCString(nil, "Port #{resource_id}: #{name}", 0)
  handle_ptr = FFI::MemoryPointer.new(:pointer)
  error = API.MIDIInputPortCreate(client, port_name, callback, nil, handle_ptr)
  handle = handle_ptr.read_pointer
  {
    error: error,
    handle: handle
  }
end

.create_midi_output_port(client, resource_id, name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



90
91
92
93
94
95
96
97
98
99
# File 'lib/midi-communications-macos/api.rb', line 90

def self.create_midi_output_port(client, resource_id, name)
  port_name = CF.CFStringCreateWithCString(nil, "Port #{resource_id}: #{name}", 0)
  port_pointer = FFI::MemoryPointer.new(:pointer)
  error = API.MIDIOutputPortCreate(client, port_name, port_pointer)
  handle = port_pointer.read_pointer
  {
    error: error,
    handle: handle
  }
end

.get_callback(*args, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



54
55
56
# File 'lib/midi-communications-macos/api.rb', line 54

def self.get_callback(*args, &block)
  FFI::Function.new(:void, *args, &block)
end

.get_int(resource, name) ⇒ Integer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • resource (FFI::Pointer)

    A pointer to an underlying struct

  • name (String, Symbol)

    The property name to get

Returns:

  • (Integer)


118
119
120
121
122
123
# File 'lib/midi-communications-macos/api.rb', line 118

def self.get_int(resource, name)
  property = API::CF.CFStringCreateWithCString(nil, name.to_s, 0)
  value = FFI::MemoryPointer.new(:pointer, 32)
  API::MIDIObjectGetIntegerProperty(resource, property, value)
  value.read_int
end

.get_midi_packet(data) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Pack the given data into a midi-communications-macos MIDI packet (used by Destination)



59
60
61
62
63
64
65
66
# File 'lib/midi-communications-macos/api.rb', line 59

def self.get_midi_packet(data)
  format = 'C' * data.size
  packed_data = data.pack(format)
  char_size = FFI.type_size(:char) * data.size
  bytes = FFI::MemoryPointer.new(char_size)
  bytes.write_string(packed_data)
  bytes
end

.get_midi_packet_list(bytes, size) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

(used by Destination)



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/midi-communications-macos/api.rb', line 102

def self.get_midi_packet_list(bytes, size)
  packet_list = FFI::MemoryPointer.new(256)
  packet_ptr = API.MIDIPacketListInit(packet_list)
  time = HostTime.AudioGetCurrentHostTime
  if X86_64
    API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time, size, bytes)
  else
    # Pass in two 32-bit 0s for the 64 bit time
    API.MIDIPacketListAdd(packet_list, 256, packet_ptr, time >> 32, time & 0xFFFFFFFF, size, bytes)
  end
  packet_list
end

.get_string(resource, name) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • resource (FFI::Pointer)

    A pointer to an underlying struct

  • name (String, Symbol)

    The property name to get

Returns:

  • (String)


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/midi-communications-macos/api.rb', line 128

def self.get_string(resource, name)
  property = CF.CFStringCreateWithCString(nil, name.to_s, 0)
  begin
    pointer = FFI::MemoryPointer.new(:pointer)
    MIDIObjectGetStringProperty(resource, property, pointer)
    string = pointer.read_pointer
    length = CF.CFStringGetMaximumSizeForEncoding(CF.CFStringGetLength(string), :kCFStringEncodingUTF8)

    bytes = FFI::MemoryPointer.new(length + 1)

    if CF.CFStringGetCString(string, bytes, length + 1, :kCFStringEncodingUTF8)
      bytes.read_string.force_encoding('utf-8')
    end
  ensure
    CF.CFRelease(string) unless string.nil? || string.null?
    CF.CFRelease(property) unless property.null?
  end
end