jack-ruby 0.1.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.
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class MidiPort < Port
5
+ def event_count(nframes)
6
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
7
+ FFI::LibJack.jack_midi_get_event_count(buf)
8
+ end
9
+
10
+ def read_event(index, nframes)
11
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
12
+ event = FFI::Structs::JackMidiEvent.new
13
+ result = FFI::LibJack.jack_midi_event_get(event, buf, index)
14
+ return nil unless result.zero?
15
+
16
+ data = event[:buffer].read_array_of_uint8(event[:size])
17
+ Midi::Event.new(event[:time], data)
18
+ end
19
+
20
+ def read_all_events(nframes)
21
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
22
+ count = FFI::LibJack.jack_midi_get_event_count(buf)
23
+ events = []
24
+ event_struct = FFI::Structs::JackMidiEvent.new
25
+
26
+ count.times do |i|
27
+ next unless FFI::LibJack.jack_midi_event_get(event_struct, buf, i).zero?
28
+
29
+ data = event_struct[:buffer].read_array_of_uint8(event_struct[:size])
30
+ events << Midi::Event.new(event_struct[:time], data)
31
+ end
32
+
33
+ events
34
+ end
35
+
36
+ def clear_buffer(nframes)
37
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
38
+ FFI::LibJack.jack_midi_clear_buffer(buf)
39
+ end
40
+
41
+ def reset_buffer(nframes)
42
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
43
+ FFI::LibJack.jack_midi_reset_buffer(buf)
44
+ rescue Jack::NotImplementedError
45
+ FFI::LibJack.jack_midi_clear_buffer(buf)
46
+ end
47
+
48
+ def reserve_event(time, data_size, nframes)
49
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
50
+ FFI::LibJack.jack_midi_event_reserve(buf, time, data_size)
51
+ end
52
+
53
+ def write_event(time, data, nframes)
54
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
55
+ data_bytes = data.is_a?(Array) ? data : data.bytes
56
+ ptr = ::FFI::MemoryPointer.new(:uint8, data_bytes.size)
57
+ ptr.write_array_of_uint8(data_bytes)
58
+ FFI::LibJack.jack_midi_event_write(buf, time, ptr, data_bytes.size)
59
+ end
60
+
61
+ def max_event_size(nframes)
62
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
63
+ FFI::LibJack.jack_midi_max_event_size(buf)
64
+ end
65
+
66
+ def lost_event_count(nframes)
67
+ buf = FFI::LibJack.jack_port_get_buffer(@handle, nframes)
68
+ FFI::LibJack.jack_midi_get_lost_event_count(buf)
69
+ end
70
+ end
71
+ end
data/lib/jack/port.rb ADDED
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class Port
5
+ attr_reader :handle, :client
6
+
7
+ def initialize(handle, client)
8
+ @handle = handle
9
+ @client = client
10
+ end
11
+
12
+ def name
13
+ FFI::LibJack.jack_port_name(@handle)
14
+ end
15
+
16
+ def short_name
17
+ FFI::LibJack.jack_port_short_name(@handle)
18
+ end
19
+
20
+ def full_name
21
+ name
22
+ end
23
+
24
+ def type
25
+ FFI::LibJack.jack_port_type(@handle)
26
+ end
27
+
28
+ def flags
29
+ FFI::LibJack.jack_port_flags(@handle)
30
+ end
31
+
32
+ def uuid
33
+ FFI::LibJack.jack_port_uuid(@handle)
34
+ end
35
+
36
+ def input?
37
+ (flags & FFI::Types::JackPortIsInput) != 0
38
+ end
39
+
40
+ def output?
41
+ (flags & FFI::Types::JackPortIsOutput) != 0
42
+ end
43
+
44
+ def physical?
45
+ (flags & FFI::Types::JackPortIsPhysical) != 0
46
+ end
47
+
48
+ def mine?
49
+ FFI::LibJack.jack_port_is_mine(@client.handle, @handle) != 0
50
+ end
51
+
52
+ def connections
53
+ ptr = FFI::LibJack.jack_port_get_connections(@handle)
54
+ return [] if ptr.null?
55
+
56
+ result = read_string_array(ptr)
57
+ FFI::LibJack.jack_free(ptr)
58
+ result
59
+ end
60
+
61
+ def connected_to?(port_name)
62
+ FFI::LibJack.jack_port_connected_to(@handle, port_name) != 0
63
+ end
64
+
65
+ def connected_count
66
+ FFI::LibJack.jack_port_connected(@handle)
67
+ end
68
+
69
+ def tie(other_port)
70
+ result = FFI::LibJack.jack_port_tie(@handle, other_port.handle)
71
+ raise Error, "Failed to tie port" unless result.zero?
72
+ rescue Jack::NotImplementedError
73
+ raise Jack::NotImplementedError, "Port tying is not available on this JACK installation"
74
+ end
75
+
76
+ def untie
77
+ result = FFI::LibJack.jack_port_untie(@handle)
78
+ raise Error, "Failed to untie port" unless result.zero?
79
+ rescue Jack::NotImplementedError
80
+ raise Jack::NotImplementedError, "Port untying is not available on this JACK installation"
81
+ end
82
+
83
+ def rename(new_name)
84
+ result = begin
85
+ FFI::LibJack.jack_port_rename(@client.handle, @handle, new_name)
86
+ rescue Jack::NotImplementedError
87
+ FFI::LibJack.jack_port_set_name(@handle, new_name)
88
+ end
89
+
90
+ raise Error, "Failed to rename port" unless result.zero?
91
+
92
+ new_name
93
+ rescue Jack::NotImplementedError
94
+ raise Jack::NotImplementedError, "Port rename is not available on this JACK installation"
95
+ end
96
+
97
+ def aliases
98
+ ptr1 = ::FFI::MemoryPointer.new(:pointer, 2)
99
+ buf1 = ::FFI::MemoryPointer.new(:char, FFI::LibJack.jack_port_name_size)
100
+ buf2 = ::FFI::MemoryPointer.new(:char, FFI::LibJack.jack_port_name_size)
101
+ ptr1.put_pointer(0, buf1)
102
+ ptr1.put_pointer(::FFI::Pointer.size, buf2)
103
+
104
+ count = FFI::LibJack.jack_port_get_aliases(@handle, ptr1)
105
+ result = []
106
+ result << buf1.read_string if count >= 1
107
+ result << buf2.read_string if count >= 2
108
+ result
109
+ end
110
+
111
+ def set_alias(alias_name)
112
+ result = FFI::LibJack.jack_port_set_alias(@handle, alias_name)
113
+ raise Error, "Failed to set alias" unless result.zero?
114
+ end
115
+
116
+ def unset_alias(alias_name)
117
+ result = FFI::LibJack.jack_port_unset_alias(@handle, alias_name)
118
+ raise Error, "Failed to unset alias" unless result.zero?
119
+ end
120
+
121
+ def capture_latency_range
122
+ range = FFI::Structs::JackLatencyRange.new
123
+ FFI::LibJack.jack_port_get_latency_range(@handle, 0, range)
124
+ { min: range[:min], max: range[:max] }
125
+ end
126
+
127
+ def playback_latency_range
128
+ range = FFI::Structs::JackLatencyRange.new
129
+ FFI::LibJack.jack_port_get_latency_range(@handle, 1, range)
130
+ { min: range[:min], max: range[:max] }
131
+ end
132
+
133
+ def set_capture_latency_range(min:, max:)
134
+ range = FFI::Structs::JackLatencyRange.new
135
+ range[:min] = min
136
+ range[:max] = max
137
+ FFI::LibJack.jack_port_set_latency_range(@handle, 0, range)
138
+ end
139
+
140
+ def latency
141
+ FFI::LibJack.jack_port_get_latency(@handle)
142
+ rescue Jack::NotImplementedError
143
+ raise Jack::NotImplementedError, "Legacy port latency is not available on this JACK installation"
144
+ end
145
+
146
+ def latency=(nframes)
147
+ FFI::LibJack.jack_port_set_latency(@handle, nframes)
148
+ rescue Jack::NotImplementedError
149
+ raise Jack::NotImplementedError, "Legacy port latency is not available on this JACK installation"
150
+ end
151
+
152
+ def total_latency
153
+ FFI::LibJack.jack_port_get_total_latency(@client.handle, @handle)
154
+ rescue Jack::NotImplementedError
155
+ raise Jack::NotImplementedError, "Legacy total port latency is not available on this JACK installation"
156
+ end
157
+
158
+ def recompute_total_latency
159
+ result = FFI::LibJack.jack_recompute_total_latency(@client.handle, @handle)
160
+ raise Error, "Failed to recompute port latency" unless result.zero?
161
+ rescue Jack::NotImplementedError
162
+ raise Jack::NotImplementedError, "Legacy total port latency recomputation is not available on this JACK installation"
163
+ end
164
+
165
+ def set_playback_latency_range(min:, max:)
166
+ range = FFI::Structs::JackLatencyRange.new
167
+ range[:min] = min
168
+ range[:max] = max
169
+ FFI::LibJack.jack_port_set_latency_range(@handle, 1, range)
170
+ end
171
+
172
+ def request_monitor(enabled)
173
+ FFI::LibJack.jack_port_request_monitor(@handle, enabled ? 1 : 0)
174
+ end
175
+
176
+ def monitoring_input?
177
+ FFI::LibJack.jack_port_monitoring_input(@handle) != 0
178
+ end
179
+
180
+ def unregister
181
+ result = FFI::LibJack.jack_port_unregister(@client.handle, @handle)
182
+ raise Error, "Failed to unregister port" unless result.zero?
183
+ end
184
+
185
+ private
186
+
187
+ def read_string_array(ptr)
188
+ result = []
189
+ offset = 0
190
+ loop do
191
+ str_ptr = ptr.get_pointer(offset)
192
+ break if str_ptr.null?
193
+
194
+ result << str_ptr.read_string
195
+ offset += ::FFI::Pointer.size
196
+ end
197
+ result
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class RingBuffer
5
+ def initialize(size)
6
+ @handle = FFI::LibJack.jack_ringbuffer_create(size)
7
+ raise Error, "Failed to create ring buffer" if @handle.null?
8
+ end
9
+
10
+ def read(count)
11
+ buf = ::FFI::MemoryPointer.new(:char, count)
12
+ bytes_read = FFI::LibJack.jack_ringbuffer_read(@handle, buf, count)
13
+ buf.read_string(bytes_read)
14
+ end
15
+
16
+ def write(data)
17
+ ptr = ::FFI::MemoryPointer.from_string(data)
18
+ FFI::LibJack.jack_ringbuffer_write(@handle, ptr, data.bytesize)
19
+ end
20
+
21
+ def peek(count)
22
+ buf = ::FFI::MemoryPointer.new(:char, count)
23
+ bytes_read = FFI::LibJack.jack_ringbuffer_peek(@handle, buf, count)
24
+ buf.read_string(bytes_read)
25
+ end
26
+
27
+ def read_space
28
+ FFI::LibJack.jack_ringbuffer_read_space(@handle)
29
+ end
30
+
31
+ def write_space
32
+ FFI::LibJack.jack_ringbuffer_write_space(@handle)
33
+ end
34
+
35
+ def read_advance(count)
36
+ FFI::LibJack.jack_ringbuffer_read_advance(@handle, count)
37
+ end
38
+
39
+ def write_advance(count)
40
+ FFI::LibJack.jack_ringbuffer_write_advance(@handle, count)
41
+ end
42
+
43
+ def reset
44
+ FFI::LibJack.jack_ringbuffer_reset(@handle)
45
+ end
46
+
47
+ def reset_size(size)
48
+ FFI::LibJack.jack_ringbuffer_reset_size(@handle, size)
49
+ rescue Jack::NotImplementedError
50
+ raise Jack::NotImplementedError, "Ring buffer resizing is not available on this JACK installation"
51
+ end
52
+
53
+ def mlock
54
+ result = FFI::LibJack.jack_ringbuffer_mlock(@handle)
55
+ raise Error, "Failed to mlock ring buffer" unless result.zero?
56
+ end
57
+
58
+ def read_vector
59
+ vec = ::FFI::MemoryPointer.new(FFI::Structs::RingBufferData, 2)
60
+ FFI::LibJack.jack_ringbuffer_get_read_vector(@handle, vec)
61
+ 2.times.map do |i|
62
+ data = FFI::Structs::RingBufferData.new(vec + (i * FFI::Structs::RingBufferData.size))
63
+ { pointer: data[:buf], length: data[:len] }
64
+ end
65
+ end
66
+
67
+ def write_vector
68
+ vec = ::FFI::MemoryPointer.new(FFI::Structs::RingBufferData, 2)
69
+ FFI::LibJack.jack_ringbuffer_get_write_vector(@handle, vec)
70
+ 2.times.map do |i|
71
+ data = FFI::Structs::RingBufferData.new(vec + (i * FFI::Structs::RingBufferData.size))
72
+ { pointer: data[:buf], length: data[:len] }
73
+ end
74
+ end
75
+
76
+ def free
77
+ return unless @handle
78
+
79
+ FFI::LibJack.jack_ringbuffer_free(@handle)
80
+ @handle = nil
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class Session
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def on_session(&block)
12
+ ffi_proc = proc { |event_ptr, _arg|
13
+ block.call(event_ptr)
14
+ }
15
+ @client.callback_manager.register(:session, block, ffi_proc)
16
+ FFI::LibJack.jack_set_session_callback(@client.handle, ffi_proc, nil)
17
+ end
18
+
19
+ def reply(event_ptr)
20
+ result = FFI::LibJack.jack_session_reply(@client.handle, event_ptr)
21
+ raise Error, "Failed to reply to session event" unless result.zero?
22
+ end
23
+
24
+ def uuid
25
+ FFI::LibJack.jack_client_get_uuid(@client.handle)
26
+ end
27
+
28
+ def notify(target: nil, type: :save, path:)
29
+ type_val = case type
30
+ when :save then 1
31
+ when :save_and_quit then 2
32
+ when :save_template then 3
33
+ else type
34
+ end
35
+
36
+ ptr = FFI::LibJack.jack_session_notify(@client.handle, target, type_val, path)
37
+ return [] if ptr.null?
38
+
39
+ commands = []
40
+ offset = 0
41
+ cmd_size = FFI::Structs::JackSessionCommand.size
42
+ loop do
43
+ cmd = FFI::Structs::JackSessionCommand.new(ptr + offset)
44
+ break if cmd[:uuid].nil?
45
+
46
+ commands << { uuid: cmd[:uuid], name: cmd[:name], command: cmd[:command], flags: cmd[:flags] }
47
+ offset += cmd_size
48
+ end
49
+
50
+ FFI::LibJack.jack_session_commands_free(ptr)
51
+ commands
52
+ end
53
+
54
+ def reserve_name(name, uuid)
55
+ result = FFI::LibJack.jack_reserve_client_name(@client.handle, name, uuid)
56
+ raise Error, "Failed to reserve client name" unless result.zero?
57
+ end
58
+
59
+ def client_has_callback?(name)
60
+ FFI::LibJack.jack_client_has_session_callback(@client.handle, name) != 0
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class Transport
5
+ STATES = {
6
+ 0 => :stopped,
7
+ 1 => :rolling,
8
+ 2 => :looping,
9
+ 3 => :starting
10
+ }.freeze
11
+ STATE_VALUES = STATES.invert.freeze
12
+
13
+ attr_reader :client
14
+
15
+ def initialize(client)
16
+ @client = client
17
+ end
18
+
19
+ def state
20
+ pos = FFI::Structs::JackPosition.new
21
+ state_val = FFI::LibJack.jack_transport_query(@client.handle, pos)
22
+ STATES[state_val] || :unknown
23
+ end
24
+
25
+ def query
26
+ pos = FFI::Structs::JackPosition.new
27
+ state_val = FFI::LibJack.jack_transport_query(@client.handle, pos)
28
+ {
29
+ state: STATES[state_val] || :unknown,
30
+ frame: pos[:frame],
31
+ frame_rate: pos[:frame_rate],
32
+ usecs: pos[:usecs],
33
+ valid: pos[:valid],
34
+ bar: pos[:bar],
35
+ beat: pos[:beat],
36
+ tick: pos[:tick],
37
+ bar_start_tick: pos[:bar_start_tick],
38
+ beats_per_bar: pos[:beats_per_bar],
39
+ beat_type: pos[:beat_type],
40
+ ticks_per_beat: pos[:ticks_per_beat],
41
+ beats_per_minute: pos[:beats_per_minute]
42
+ }
43
+ end
44
+
45
+ def legacy_info
46
+ info = FFI::Structs::JackTransportInfo.new
47
+ FFI::LibJack.jack_get_transport_info(@client.handle, info)
48
+
49
+ {
50
+ frame_rate: info[:frame_rate],
51
+ usecs: info[:usecs],
52
+ valid: info[:valid],
53
+ transport_state: STATES[info[:transport_state]] || :unknown,
54
+ frame: info[:frame],
55
+ loop_start: info[:loop_start],
56
+ loop_end: info[:loop_end],
57
+ smpte_offset: info[:smpte_offset],
58
+ smpte_frame_rate: info[:smpte_frame_rate],
59
+ bar: info[:bar],
60
+ beat: info[:beat],
61
+ tick: info[:tick],
62
+ bar_start_tick: info[:bar_start_tick],
63
+ beats_per_bar: info[:beats_per_bar],
64
+ beat_type: info[:beat_type],
65
+ ticks_per_beat: info[:ticks_per_beat],
66
+ beats_per_minute: info[:beats_per_minute]
67
+ }
68
+ rescue Jack::NotImplementedError
69
+ raise Jack::NotImplementedError, "Legacy transport info is not available on this JACK installation"
70
+ end
71
+
72
+ def legacy_info=(values)
73
+ info = FFI::Structs::JackTransportInfo.new
74
+ values.each do |key, value|
75
+ next unless info.members.include?(key)
76
+
77
+ info[key] = key == :transport_state && value.is_a?(Symbol) ? STATE_VALUES.fetch(value, value) : value
78
+ end
79
+ FFI::LibJack.jack_set_transport_info(@client.handle, info)
80
+ rescue Jack::NotImplementedError
81
+ raise Jack::NotImplementedError, "Legacy transport info is not available on this JACK installation"
82
+ end
83
+
84
+ def frame
85
+ FFI::LibJack.jack_get_current_transport_frame(@client.handle)
86
+ end
87
+
88
+ def start
89
+ FFI::LibJack.jack_transport_start(@client.handle)
90
+ end
91
+
92
+ def stop
93
+ FFI::LibJack.jack_transport_stop(@client.handle)
94
+ end
95
+
96
+ def locate(frame_pos)
97
+ result = FFI::LibJack.jack_transport_locate(@client.handle, frame_pos)
98
+ raise Error, "Failed to locate transport" unless result.zero?
99
+ end
100
+
101
+ def reposition(position_hash)
102
+ pos = FFI::Structs::JackPosition.new
103
+ position_hash.each do |key, value|
104
+ pos[key] = value if pos.members.include?(key)
105
+ end
106
+ result = FFI::LibJack.jack_transport_reposition(@client.handle, pos)
107
+ raise Error, "Failed to reposition transport" unless result.zero?
108
+ end
109
+
110
+ def on_sync(&block)
111
+ ffi_proc = proc { |state, pos_ptr, _arg|
112
+ block.call(STATES[state] || :unknown, pos_ptr) ? 1 : 0
113
+ }
114
+ @client.callback_manager.register(:sync, block, ffi_proc)
115
+ FFI::LibJack.jack_set_sync_callback(@client.handle, ffi_proc, nil)
116
+ end
117
+
118
+ def sync_timeout=(usecs)
119
+ FFI::LibJack.jack_set_sync_timeout(@client.handle, usecs)
120
+ end
121
+
122
+ def set_timebase(conditional: false, &block)
123
+ ffi_proc = proc { |state, nframes, pos_ptr, new_pos, _arg|
124
+ block.call(STATES[state] || :unknown, nframes, pos_ptr, new_pos != 0)
125
+ }
126
+ @client.callback_manager.register(:timebase, block, ffi_proc)
127
+ result = FFI::LibJack.jack_set_timebase_callback(
128
+ @client.handle, conditional ? 1 : 0, ffi_proc, nil
129
+ )
130
+ raise Error, "Failed to set timebase callback" unless result.zero?
131
+ end
132
+
133
+ def release_timebase
134
+ result = FFI::LibJack.jack_release_timebase(@client.handle)
135
+ raise Error, "Failed to release timebase" unless result.zero?
136
+ end
137
+ end
138
+ end
data/lib/jack/uuid.rb ADDED
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ module UUID
5
+ module_function
6
+
7
+ def generate_client
8
+ FFI::LibJack.jack_client_uuid_generate
9
+ end
10
+
11
+ def generate_port(port_id)
12
+ FFI::LibJack.jack_port_uuid_generate(port_id)
13
+ end
14
+
15
+ def to_index(uuid)
16
+ FFI::LibJack.jack_uuid_to_index(uuid)
17
+ end
18
+
19
+ def compare(left, right)
20
+ FFI::LibJack.jack_uuid_compare(left, right)
21
+ end
22
+
23
+ def copy(uuid)
24
+ pointer = ::FFI::MemoryPointer.new(:uint64)
25
+ FFI::LibJack.jack_uuid_copy(pointer, uuid)
26
+ pointer.read_uint64
27
+ end
28
+
29
+ def clear(uuid)
30
+ pointer = ::FFI::MemoryPointer.new(:uint64)
31
+ pointer.write_uint64(uuid)
32
+ FFI::LibJack.jack_uuid_clear(pointer)
33
+ pointer.read_uint64
34
+ end
35
+
36
+ def parse(value)
37
+ pointer = ::FFI::MemoryPointer.new(:uint64)
38
+ result = FFI::LibJack.jack_uuid_parse(value, pointer)
39
+ raise Error, "Failed to parse UUID '#{value}'" unless result.zero?
40
+
41
+ pointer.read_uint64
42
+ end
43
+
44
+ def unparse(uuid)
45
+ pointer = ::FFI::MemoryPointer.new(:char, FFI::Types::JACK_UUID_STRING_SIZE)
46
+ FFI::LibJack.jack_uuid_unparse(uuid, pointer)
47
+ pointer.read_string
48
+ end
49
+
50
+ def empty?(uuid)
51
+ FFI::LibJack.jack_uuid_empty(uuid) != 0
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ VERSION = "0.1.0"
5
+ end
data/lib/jack.rb ADDED
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ require_relative "jack/version"
6
+ require_relative "jack/error"
7
+ require_relative "jack/ffi/types"
8
+ require_relative "jack/ffi/structs"
9
+ require_relative "jack/ffi/lib_jack"
10
+ require_relative "jack/callback_manager"
11
+ require_relative "jack/port"
12
+ require_relative "jack/audio_port"
13
+ require_relative "jack/midi/event"
14
+ require_relative "jack/midi_port"
15
+ require_relative "jack/transport"
16
+ require_relative "jack/session"
17
+ require_relative "jack/ring_buffer"
18
+ require_relative "jack/metadata"
19
+ require_relative "jack/uuid"
20
+ require_relative "jack/client"
21
+
22
+ module Jack
23
+ # Re-export commonly used constants for convenience
24
+ JackPortIsInput = FFI::Types::JackPortIsInput
25
+ JackPortIsOutput = FFI::Types::JackPortIsOutput
26
+ JackPortIsPhysical = FFI::Types::JackPortIsPhysical
27
+ JackPortCanMonitor = FFI::Types::JackPortCanMonitor
28
+ JackPortIsTerminal = FFI::Types::JackPortIsTerminal
29
+
30
+ JACK_DEFAULT_AUDIO_TYPE = FFI::Types::JACK_DEFAULT_AUDIO_TYPE
31
+ JACK_DEFAULT_MIDI_TYPE = FFI::Types::JACK_DEFAULT_MIDI_TYPE
32
+
33
+ class << self
34
+ def version
35
+ pointers = Array.new(4) { ::FFI::MemoryPointer.new(:int) }
36
+ FFI::LibJack.jack_get_version(*pointers)
37
+
38
+ {
39
+ major: pointers[0].read_int,
40
+ minor: pointers[1].read_int,
41
+ micro: pointers[2].read_int,
42
+ protocol: pointers[3].read_int
43
+ }
44
+ end
45
+
46
+ def version_string
47
+ FFI::LibJack.jack_get_version_string
48
+ end
49
+
50
+ def client_pid(name)
51
+ FFI::LibJack.jack_get_client_pid(name)
52
+ end
53
+
54
+ def on_error(&block)
55
+ @error_callback = block && proc { |message| block.call(message) }
56
+ FFI::LibJack.jack_set_error_function(@error_callback)
57
+ end
58
+
59
+ def on_info(&block)
60
+ @info_callback = block && proc { |message| block.call(message) }
61
+ FFI::LibJack.jack_set_info_function(@info_callback)
62
+ end
63
+ end
64
+ end