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,306 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+
5
+ module Jack
6
+ module FFI
7
+ module LibJack
8
+ extend ::FFI::Library
9
+
10
+ LIBRARY_NAMES = case RbConfig::CONFIG["host_os"]
11
+ when /linux/
12
+ ["libjack.so.0", "libjack.so"]
13
+ when /darwin/
14
+ ["libjack.0.dylib", "libjack.dylib",
15
+ "/opt/homebrew/lib/libjack.0.dylib",
16
+ "/opt/homebrew/lib/libjack.dylib",
17
+ "/opt/homebrew/opt/jack/lib/libjack.0.dylib",
18
+ "/opt/homebrew/opt/jack/lib/libjack.dylib",
19
+ "/usr/local/opt/jack/lib/libjack.0.dylib",
20
+ "/usr/local/lib/libjack.dylib",
21
+ "/usr/local/opt/jack/lib/libjack.dylib",
22
+ "/usr/local/lib/libjack.0.dylib"]
23
+ when /mswin|mingw/
24
+ ["libjack64.dll", "libjack.dll"]
25
+ else
26
+ ["libjack.so.0", "libjack.so"]
27
+ end
28
+
29
+ def self.load_library
30
+ library_names = ENV["JACK_LIB_PATH"] ? [ENV["JACK_LIB_PATH"]] : LIBRARY_NAMES
31
+ last_error = nil
32
+
33
+ library_names.each do |library_name|
34
+ ffi_lib library_name
35
+ return
36
+ rescue LoadError => e
37
+ last_error = e
38
+ end
39
+
40
+ raise last_error if last_error
41
+ rescue LoadError => e
42
+ raise Jack::Error,
43
+ "libjack not found. Please install JACK: #{e.message}"
44
+ end
45
+
46
+ def self.function_available?(name)
47
+ ffi_libraries.any? do |lib|
48
+ !lib.find_function(name.to_s).nil?
49
+ end
50
+ rescue StandardError
51
+ false
52
+ end
53
+
54
+ def self.attach_optional(name, args, ret)
55
+ if function_available?(name)
56
+ attach_function name, args, ret
57
+ true
58
+ else
59
+ define_singleton_method(name) { |*| raise Jack::NotImplementedError, "#{name} is not available" }
60
+ false
61
+ end
62
+ end
63
+
64
+ include Types
65
+ Types.apply_to(self)
66
+
67
+ begin
68
+ load_library
69
+ @library_loaded = true
70
+ @load_error = nil
71
+ rescue Jack::Error => e
72
+ @library_loaded = false
73
+ @load_error = e
74
+ end
75
+
76
+ def self.library_loaded?
77
+ @library_loaded
78
+ end
79
+
80
+ def self.ensure_loaded!
81
+ return if @library_loaded
82
+
83
+ raise(@load_error || Jack::Error.new("libjack not found. Please install JACK or set JACK_LIB_PATH"))
84
+ end
85
+
86
+ def self.method_missing(name, *args, &block)
87
+ if name.to_s.start_with?("jack_") && !@library_loaded
88
+ ensure_loaded!
89
+ else
90
+ super
91
+ end
92
+ end
93
+
94
+ def self.respond_to_missing?(name, include_private = false)
95
+ (name.to_s.start_with?("jack_") && !@library_loaded) || super
96
+ end
97
+
98
+ if @library_loaded # rubocop:disable Style/IfUnlessModifier
99
+
100
+ # === Client management (jack.h) ===
101
+ attach_function :jack_client_open, [:string, :int, :pointer, :varargs], :jack_client_t
102
+ attach_optional :jack_client_new, [:string], :jack_client_t
103
+ attach_function :jack_client_close, [:jack_client_t], :int
104
+ attach_function :jack_client_name_size, [], :int
105
+ attach_optional :jack_get_version, [:pointer, :pointer, :pointer, :pointer], :void
106
+ attach_optional :jack_get_version_string, [], :string
107
+ attach_function :jack_get_client_name, [:jack_client_t], :string
108
+ attach_function :jack_get_uuid_for_client_name, [:jack_client_t, :string], :string
109
+ attach_function :jack_get_client_name_by_uuid, [:jack_client_t, :string], :string
110
+ attach_function :jack_activate, [:jack_client_t], :int
111
+ attach_function :jack_deactivate, [:jack_client_t], :int
112
+ attach_optional :jack_get_client_pid, [:string], :int
113
+ attach_function :jack_client_thread_id, [:jack_client_t], :ulong
114
+ attach_function :jack_is_realtime, [:jack_client_t], :int
115
+ attach_optional :jack_set_error_function, [:JackMessageCallback], :void
116
+ attach_optional :jack_set_info_function, [:JackMessageCallback], :void
117
+
118
+ # === Callback registration (jack.h) ===
119
+ attach_function :jack_set_process_callback, [:jack_client_t, :JackProcessCallback, :pointer], :int
120
+ attach_function :jack_set_thread_init_callback, [:jack_client_t, :JackThreadInitCallback, :pointer], :int
121
+ attach_function :jack_on_shutdown, [:jack_client_t, :JackShutdownCallback, :pointer], :void
122
+ attach_function :jack_on_info_shutdown, [:jack_client_t, :JackInfoShutdownCallback, :pointer], :void
123
+ attach_function :jack_set_freewheel_callback, [:jack_client_t, :JackFreewheelCallback, :pointer], :int
124
+ attach_function :jack_set_buffer_size_callback, [:jack_client_t, :JackBufferSizeCallback, :pointer], :int
125
+ attach_function :jack_set_sample_rate_callback, [:jack_client_t, :JackSampleRateCallback, :pointer], :int
126
+ attach_function :jack_set_client_registration_callback, [:jack_client_t, :JackClientRegistrationCallback, :pointer], :int
127
+ attach_function :jack_set_port_registration_callback, [:jack_client_t, :JackPortRegistrationCallback, :pointer], :int
128
+ attach_optional :jack_set_port_rename_callback, [:jack_client_t, :JackPortRenameCallback, :pointer], :int
129
+ attach_function :jack_set_port_connect_callback, [:jack_client_t, :JackPortConnectCallback, :pointer], :int
130
+ attach_function :jack_set_graph_order_callback, [:jack_client_t, :JackGraphOrderCallback, :pointer], :int
131
+ attach_function :jack_set_xrun_callback, [:jack_client_t, :JackXRunCallback, :pointer], :int
132
+ attach_function :jack_set_latency_callback, [:jack_client_t, :JackLatencyCallback, :pointer], :int
133
+
134
+ # === Non-Callback API (jack.h) ===
135
+ attach_function :jack_set_process_thread, [:jack_client_t, :JackThreadCallback, :pointer], :int
136
+ attach_optional :jack_thread_wait, [:jack_client_t, :int], :uint32
137
+ attach_function :jack_cycle_wait, [:jack_client_t], :uint32
138
+ attach_function :jack_cycle_signal, [:jack_client_t, :int], :void
139
+
140
+ # === Server control (jack.h) ===
141
+ attach_optional :jack_engine_takeover_timebase, [:jack_client_t], :int
142
+ attach_function :jack_set_freewheel, [:jack_client_t, :int], :int
143
+ attach_function :jack_set_buffer_size, [:jack_client_t, :uint32], :int
144
+ attach_function :jack_get_sample_rate, [:jack_client_t], :uint32
145
+ attach_function :jack_get_buffer_size, [:jack_client_t], :uint32
146
+ attach_function :jack_cpu_load, [:jack_client_t], :float
147
+
148
+ # === Port functions (jack.h) ===
149
+ attach_function :jack_port_register, [:jack_client_t, :string, :string, :ulong, :ulong], :jack_port_t
150
+ attach_function :jack_port_unregister, [:jack_client_t, :jack_port_t], :int
151
+ attach_function :jack_port_get_buffer, [:jack_port_t, :uint32], :pointer
152
+ attach_function :jack_port_uuid, [:jack_port_t], :uint64
153
+ attach_function :jack_port_name, [:jack_port_t], :string
154
+ attach_function :jack_port_short_name, [:jack_port_t], :string
155
+ attach_function :jack_port_flags, [:jack_port_t], :int
156
+ attach_function :jack_port_type, [:jack_port_t], :string
157
+ attach_function :jack_port_type_id, [:jack_port_t], :uint32
158
+ attach_function :jack_port_is_mine, [:jack_client_t, :jack_port_t], :int
159
+ attach_function :jack_port_connected, [:jack_port_t], :int
160
+ attach_function :jack_port_connected_to, [:jack_port_t, :string], :int
161
+ attach_function :jack_port_get_connections, [:jack_port_t], :pointer
162
+ attach_function :jack_port_get_all_connections, [:jack_client_t, :jack_port_t], :pointer
163
+ attach_optional :jack_port_tie, [:jack_port_t, :jack_port_t], :int
164
+ attach_optional :jack_port_untie, [:jack_port_t], :int
165
+ attach_optional :jack_port_rename, [:jack_client_t, :jack_port_t, :string], :int
166
+ attach_optional :jack_port_set_name, [:jack_port_t, :string], :int
167
+ attach_function :jack_port_set_alias, [:jack_port_t, :string], :int
168
+ attach_function :jack_port_unset_alias, [:jack_port_t, :string], :int
169
+ attach_function :jack_port_get_aliases, [:jack_port_t, :pointer], :int
170
+ attach_function :jack_port_request_monitor, [:jack_port_t, :int], :int
171
+ attach_function :jack_port_request_monitor_by_name, [:jack_client_t, :string, :int], :int
172
+ attach_function :jack_port_ensure_monitor, [:jack_port_t, :int], :int
173
+ attach_function :jack_port_monitoring_input, [:jack_port_t], :int
174
+ attach_function :jack_connect, [:jack_client_t, :string, :string], :int
175
+ attach_function :jack_disconnect, [:jack_client_t, :string, :string], :int
176
+ attach_function :jack_port_disconnect, [:jack_client_t, :jack_port_t], :int
177
+ attach_function :jack_port_name_size, [], :int
178
+ attach_function :jack_port_type_size, [], :int
179
+ attach_function :jack_port_type_get_buffer_size, [:jack_client_t, :string], :size_t
180
+
181
+ # === Latency (jack.h) ===
182
+ attach_optional :jack_port_set_latency, [:jack_port_t, :uint32], :void
183
+ attach_function :jack_port_set_latency_range, [:jack_port_t, :int, :pointer], :void
184
+ attach_optional :jack_port_get_latency, [:jack_port_t], :uint32
185
+ attach_function :jack_port_get_latency_range, [:jack_port_t, :int, :pointer], :void
186
+ attach_optional :jack_port_get_total_latency, [:jack_client_t, :jack_port_t], :uint32
187
+ attach_function :jack_recompute_total_latencies, [:jack_client_t], :int
188
+ attach_optional :jack_recompute_total_latency, [:jack_client_t, :jack_port_t], :int
189
+
190
+ # === Port searching (jack.h) ===
191
+ attach_function :jack_get_ports, [:jack_client_t, :string, :string, :ulong], :pointer
192
+ attach_function :jack_port_by_name, [:jack_client_t, :string], :jack_port_t
193
+ attach_function :jack_port_by_id, [:jack_client_t, :uint32], :jack_port_t
194
+
195
+ # === Time functions (jack.h) ===
196
+ attach_function :jack_frames_since_cycle_start, [:jack_client_t], :uint32
197
+ attach_function :jack_frame_time, [:jack_client_t], :uint32
198
+ attach_function :jack_last_frame_time, [:jack_client_t], :uint32
199
+ attach_function :jack_get_cycle_times, [:jack_client_t, :pointer, :pointer, :pointer, :pointer], :int
200
+ attach_function :jack_frames_to_time, [:jack_client_t, :uint32], :uint64
201
+ attach_function :jack_time_to_frames, [:jack_client_t, :uint64], :uint32
202
+ attach_function :jack_get_time, [], :uint64
203
+
204
+ # === Memory (jack.h) ===
205
+ attach_function :jack_free, [:pointer], :void
206
+
207
+ # === MIDI API (midiport.h) ===
208
+ attach_function :jack_midi_get_event_count, [:pointer], :uint32
209
+ attach_function :jack_midi_event_get, [:pointer, :pointer, :uint32], :int
210
+ attach_function :jack_midi_clear_buffer, [:pointer], :void
211
+ attach_optional :jack_midi_reset_buffer, [:pointer], :void
212
+ attach_function :jack_midi_max_event_size, [:pointer], :size_t
213
+ attach_function :jack_midi_event_reserve, [:pointer, :uint32, :size_t], :pointer
214
+ attach_function :jack_midi_event_write, [:pointer, :uint32, :pointer, :size_t], :int
215
+ attach_function :jack_midi_get_lost_event_count, [:pointer], :uint32
216
+
217
+ # === Transport API (transport.h) ===
218
+ attach_function :jack_release_timebase, [:jack_client_t], :int
219
+ attach_function :jack_set_sync_callback, [:jack_client_t, :JackSyncCallback, :pointer], :int
220
+ attach_function :jack_set_sync_timeout, [:jack_client_t, :uint64], :int
221
+ attach_function :jack_set_timebase_callback, [:jack_client_t, :int, :JackTimebaseCallback, :pointer], :int
222
+ attach_function :jack_transport_locate, [:jack_client_t, :uint32], :int
223
+ attach_function :jack_transport_query, [:jack_client_t, :pointer], :int
224
+ attach_optional :jack_get_transport_info, [:jack_client_t, :pointer], :void
225
+ attach_function :jack_get_current_transport_frame, [:jack_client_t], :uint32
226
+ attach_optional :jack_set_transport_info, [:jack_client_t, :pointer], :void
227
+ attach_function :jack_transport_reposition, [:jack_client_t, :pointer], :int
228
+ attach_function :jack_transport_start, [:jack_client_t], :void
229
+ attach_function :jack_transport_stop, [:jack_client_t], :void
230
+
231
+ # === Session API (session.h) ===
232
+ attach_optional :jack_set_session_callback, [:jack_client_t, :JackSessionCallback, :pointer], :int
233
+ attach_optional :jack_session_reply, [:jack_client_t, :pointer], :int
234
+ attach_optional :jack_session_event_free, [:pointer], :void
235
+ attach_function :jack_client_get_uuid, [:jack_client_t], :string
236
+ attach_optional :jack_session_notify, [:jack_client_t, :string, :int, :string], :pointer
237
+ attach_optional :jack_session_commands_free, [:pointer], :void
238
+ attach_optional :jack_reserve_client_name, [:jack_client_t, :string, :string], :int
239
+ attach_optional :jack_client_has_session_callback, [:jack_client_t, :string], :int
240
+
241
+ # === Internal client API (intclient.h) ===
242
+ attach_optional :jack_get_internal_client_name, [:jack_client_t, :jack_intclient_t], :pointer
243
+ attach_optional :jack_internal_client_handle, [:jack_client_t, :string, :pointer], :jack_intclient_t
244
+ attach_optional :jack_internal_client_load, [:jack_client_t, :string, :int, :pointer, :varargs], :jack_intclient_t
245
+ attach_optional :jack_internal_client_unload, [:jack_client_t, :jack_intclient_t], :int
246
+ attach_optional :jack_internal_client_new, [:string, :string, :string], :int
247
+ attach_optional :jack_internal_client_close, [:string], :void
248
+
249
+ # === RingBuffer API (ringbuffer.h) ===
250
+ attach_function :jack_ringbuffer_create, [:size_t], :pointer
251
+ attach_function :jack_ringbuffer_free, [:pointer], :void
252
+ attach_function :jack_ringbuffer_get_read_vector, [:pointer, :pointer], :void
253
+ attach_function :jack_ringbuffer_get_write_vector, [:pointer, :pointer], :void
254
+ attach_function :jack_ringbuffer_read, [:pointer, :pointer, :size_t], :size_t
255
+ attach_function :jack_ringbuffer_peek, [:pointer, :pointer, :size_t], :size_t
256
+ attach_function :jack_ringbuffer_read_advance, [:pointer, :size_t], :void
257
+ attach_function :jack_ringbuffer_read_space, [:pointer], :size_t
258
+ attach_function :jack_ringbuffer_mlock, [:pointer], :int
259
+ attach_function :jack_ringbuffer_reset, [:pointer], :void
260
+ attach_optional :jack_ringbuffer_reset_size, [:pointer, :size_t], :void
261
+ attach_function :jack_ringbuffer_write, [:pointer, :pointer, :size_t], :size_t
262
+ attach_function :jack_ringbuffer_write_advance, [:pointer, :size_t], :void
263
+ attach_function :jack_ringbuffer_write_space, [:pointer], :size_t
264
+
265
+ # === Metadata API (metadata.h) - JACK2 only ===
266
+ attach_optional :jack_set_property, [:jack_client_t, :uint64, :string, :string, :string], :int
267
+ attach_optional :jack_get_property, [:uint64, :string, :pointer, :pointer], :int
268
+ attach_optional :jack_free_description, [:pointer, :int], :void
269
+ attach_optional :jack_get_properties, [:uint64, :pointer], :int
270
+ attach_optional :jack_get_all_properties, [:pointer], :int
271
+ attach_optional :jack_remove_property, [:jack_client_t, :uint64, :string], :int
272
+ attach_optional :jack_remove_properties, [:jack_client_t, :uint64], :int
273
+ attach_optional :jack_remove_all_properties, [:jack_client_t], :int
274
+ attach_optional :jack_set_property_change_callback, [:jack_client_t, :JackPropertyChangeCallback, :pointer], :int
275
+
276
+ # === Statistics API (statistics.h) ===
277
+ attach_optional :jack_get_max_delayed_usecs, [:jack_client_t], :float
278
+ attach_optional :jack_get_xrun_delayed_usecs, [:jack_client_t], :float
279
+ attach_optional :jack_reset_max_delayed_usecs, [:jack_client_t], :void
280
+ attach_optional :jack_max_cpu_load, [:jack_client_t], :float
281
+
282
+ # === Thread API (thread.h) ===
283
+ attach_optional :jack_client_real_time_priority, [:jack_client_t], :int
284
+ attach_optional :jack_client_max_real_time_priority, [:jack_client_t], :int
285
+ attach_optional :jack_acquire_real_time_scheduling, [:ulong, :int], :int
286
+ attach_optional :jack_drop_real_time_scheduling, [:ulong], :int
287
+ attach_optional :jack_client_create_thread, [:jack_client_t, :pointer, :int, :int, :JackThreadCallback, :pointer], :int
288
+ attach_optional :jack_client_stop_thread, [:jack_client_t, :ulong], :int
289
+ attach_optional :jack_client_kill_thread, [:jack_client_t, :ulong], :int
290
+ attach_optional :jack_set_thread_creator, [:pointer], :void
291
+
292
+ # === UUID API (uuid.h) ===
293
+ attach_function :jack_client_uuid_generate, [], :jack_uuid_t
294
+ attach_function :jack_port_uuid_generate, [:uint32], :jack_uuid_t
295
+ attach_function :jack_uuid_to_index, [:jack_uuid_t], :uint32
296
+ attach_function :jack_uuid_compare, [:jack_uuid_t, :jack_uuid_t], :int
297
+ attach_function :jack_uuid_copy, [:pointer, :jack_uuid_t], :void
298
+ attach_function :jack_uuid_clear, [:pointer], :void
299
+ attach_function :jack_uuid_parse, [:string, :pointer], :int
300
+ attach_function :jack_uuid_unparse, [:jack_uuid_t, :pointer], :void
301
+ attach_function :jack_uuid_empty, [:jack_uuid_t], :int
302
+
303
+ end # if @library_loaded
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ module FFI
5
+ module Structs
6
+ class JackLatencyRange < ::FFI::Struct
7
+ layout :min, :uint32,
8
+ :max, :uint32
9
+ end
10
+
11
+ class JackPosition < ::FFI::Struct
12
+ layout :unique_1, :uint64,
13
+ :usecs, :uint64,
14
+ :frame_rate, :uint32,
15
+ :frame, :uint32,
16
+ :valid, :int,
17
+ :bar, :int32,
18
+ :beat, :int32,
19
+ :tick, :int32,
20
+ :bar_start_tick, :double,
21
+ :beats_per_bar, :float,
22
+ :beat_type, :float,
23
+ :ticks_per_beat, :double,
24
+ :beats_per_minute, :double,
25
+ :frame_time, :double,
26
+ :next_time, :double,
27
+ :bbt_offset, :uint32,
28
+ :audio_frames_per_video_frame, :float,
29
+ :video_offset, :uint32,
30
+ :tick_double, :double,
31
+ :padding, [:int32, 5],
32
+ :unique_2, :uint64
33
+ end
34
+
35
+ class JackTransportInfo < ::FFI::Struct
36
+ layout :frame_rate, :uint32,
37
+ :usecs, :uint64,
38
+ :valid, :int,
39
+ :transport_state, :int,
40
+ :frame, :uint32,
41
+ :loop_start, :uint32,
42
+ :loop_end, :uint32,
43
+ :smpte_offset, :long,
44
+ :smpte_frame_rate, :float,
45
+ :bar, :int,
46
+ :beat, :int,
47
+ :tick, :int,
48
+ :bar_start_tick, :double,
49
+ :beats_per_bar, :float,
50
+ :beat_type, :float,
51
+ :ticks_per_beat, :double,
52
+ :beats_per_minute, :double
53
+ end
54
+
55
+ class JackMidiEvent < ::FFI::Struct
56
+ layout :time, :uint32,
57
+ :size, :size_t,
58
+ :buffer, :pointer
59
+ end
60
+
61
+ class JackSessionCommand < ::FFI::Struct
62
+ layout :uuid, :string,
63
+ :name, :string,
64
+ :command, :string,
65
+ :flags, :int
66
+ end
67
+
68
+ class RingBufferData < ::FFI::Struct
69
+ layout :buf, :pointer,
70
+ :len, :size_t
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ module FFI
5
+ module Types
6
+ TYPEDEFS = {
7
+ jack_nframes_t: :uint32,
8
+ jack_time_t: :uint64,
9
+ jack_uuid_t: :uint64,
10
+ jack_client_t: :pointer,
11
+ jack_port_t: :pointer,
12
+ jack_intclient_t: :uint64,
13
+ jack_midi_data_t: :uchar,
14
+ jack_default_audio_sample_t: :float
15
+ }.freeze
16
+
17
+ LATENCY_CALLBACK_MODE = [
18
+ :JackCaptureLatency, 0,
19
+ :JackPlaybackLatency, 1
20
+ ].freeze
21
+
22
+ TRANSPORT_STATE = [
23
+ :JackTransportStopped, 0,
24
+ :JackTransportRolling, 1,
25
+ :JackTransportLooping, 2,
26
+ :JackTransportStarting, 3
27
+ ].freeze
28
+
29
+ SESSION_EVENT_TYPE = [
30
+ :JackSessionSave, 1,
31
+ :JackSessionSaveAndQuit, 2,
32
+ :JackSessionSaveTemplate, 3
33
+ ].freeze
34
+
35
+ CALLBACKS = {
36
+ JackProcessCallback: [[:jack_nframes_t, :pointer], :int],
37
+ JackShutdownCallback: [[:pointer], :void],
38
+ JackInfoShutdownCallback: [[:int, :string, :pointer], :void],
39
+ JackSampleRateCallback: [[:jack_nframes_t, :pointer], :int],
40
+ JackBufferSizeCallback: [[:jack_nframes_t, :pointer], :int],
41
+ JackXRunCallback: [[:pointer], :int],
42
+ JackPortRegistrationCallback: [[:uint32, :int, :pointer], :void],
43
+ JackClientRegistrationCallback: [[:string, :int, :pointer], :void],
44
+ JackPortConnectCallback: [[:uint32, :uint32, :int, :pointer], :void],
45
+ JackPortRenameCallback: [[:uint32, :string, :string, :pointer], :int],
46
+ JackFreewheelCallback: [[:int, :pointer], :void],
47
+ JackGraphOrderCallback: [[:pointer], :int],
48
+ JackThreadInitCallback: [[:pointer], :void],
49
+ JackLatencyCallback: [[:jack_latency_callback_mode_t, :pointer], :void],
50
+ JackThreadCallback: [[:pointer], :pointer],
51
+ JackSyncCallback: [[:jack_transport_state_t, :pointer, :pointer], :int],
52
+ JackTimebaseCallback: [[:jack_transport_state_t, :jack_nframes_t, :pointer, :int, :pointer], :void],
53
+ JackSessionCallback: [[:pointer, :pointer], :void],
54
+ JackPropertyChangeCallback: [[:jack_uuid_t, :string, :int, :pointer], :void],
55
+ JackMessageCallback: [[:string], :void]
56
+ }.freeze
57
+
58
+ def self.apply_to(target)
59
+ TYPEDEFS.each do |name, native_type|
60
+ target.typedef(native_type, name)
61
+ end
62
+
63
+ target.enum(:jack_latency_callback_mode_t, LATENCY_CALLBACK_MODE)
64
+ target.enum(:jack_transport_state_t, TRANSPORT_STATE)
65
+ target.enum(:jack_session_event_type_t, SESSION_EVENT_TYPE)
66
+
67
+ CALLBACKS.each do |name, (params, return_type)|
68
+ target.callback(name, params, return_type)
69
+ end
70
+ end
71
+
72
+ JACK_UUID_SIZE = 36
73
+ JACK_UUID_STRING_SIZE = JACK_UUID_SIZE + 1
74
+
75
+ # jack_options_t (bit flags)
76
+ JackNullOption = 0x00
77
+ JackNoStartServer = 0x01
78
+ JackUseExactName = 0x02
79
+ JackServerName = 0x04
80
+ JackLoadName = 0x08
81
+ JackLoadInit = 0x10
82
+ JackSessionID = 0x20
83
+
84
+ # jack_status_t (bit flags)
85
+ JackFailure = 0x01
86
+ JackInvalidOption = 0x02
87
+ JackNameNotUnique = 0x04
88
+ JackServerStarted = 0x08
89
+ JackServerFailed = 0x10
90
+ JackServerError = 0x20
91
+ JackNoSuchClient = 0x40
92
+ JackLoadFailure = 0x80
93
+ JackInitFailure = 0x100
94
+ JackShmFailure = 0x200
95
+ JackVersionError = 0x400
96
+ JackBackendError = 0x800
97
+ JackClientZombie = 0x1000
98
+
99
+ # JackPortFlags
100
+ JackPortIsInput = 0x1
101
+ JackPortIsOutput = 0x2
102
+ JackPortIsPhysical = 0x4
103
+ JackPortCanMonitor = 0x8
104
+ JackPortIsTerminal = 0x10
105
+
106
+ # jack_position_bits_t
107
+ JackPositionBBT = 0x10
108
+ JackPositionTimecode = 0x20
109
+ JackBBTFrameOffset = 0x40
110
+ JackAudioVideoRatio = 0x80
111
+ JackVideoFrameOffset = 0x100
112
+ JackTickDouble = 0x200
113
+
114
+ # jack_session_flags_t
115
+ JackSessionSaveError = 0x01
116
+ JackSessionNeedTerminal = 0x02
117
+
118
+ # Port type constants
119
+ JACK_DEFAULT_AUDIO_TYPE = "32 bit float mono audio"
120
+ JACK_DEFAULT_MIDI_TYPE = "8 bit raw midi"
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ class Metadata
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def set_property(subject, key, value, type = "")
12
+ result = FFI::LibJack.jack_set_property(@client.handle, subject, key, value, type)
13
+ raise Error, "Failed to set property" unless result.zero?
14
+ end
15
+
16
+ def get_property(subject, key)
17
+ value_ptr = ::FFI::MemoryPointer.new(:pointer)
18
+ type_ptr = ::FFI::MemoryPointer.new(:pointer)
19
+ result = FFI::LibJack.jack_get_property(subject, key, value_ptr, type_ptr)
20
+ return nil unless result.zero?
21
+
22
+ value = value_ptr.read_pointer.read_string
23
+ type = type_ptr.read_pointer.read_string
24
+ { value: value, type: type }
25
+ end
26
+
27
+ def remove_property(subject, key)
28
+ result = FFI::LibJack.jack_remove_property(@client.handle, subject, key)
29
+ raise Error, "Failed to remove property" unless result.zero?
30
+ end
31
+
32
+ def remove_properties(subject)
33
+ result = FFI::LibJack.jack_remove_properties(@client.handle, subject)
34
+ raise Error, "Failed to remove properties" unless result.zero?
35
+ end
36
+
37
+ def remove_all_properties
38
+ result = FFI::LibJack.jack_remove_all_properties(@client.handle)
39
+ raise Error, "Failed to remove all properties" unless result.zero?
40
+ end
41
+
42
+ def on_property_change(&block)
43
+ ffi_proc = proc { |subject, key, change, _arg|
44
+ block.call(subject, key, change)
45
+ }
46
+ @client.callback_manager.register(:property_change, block, ffi_proc)
47
+ FFI::LibJack.jack_set_property_change_callback(@client.handle, ffi_proc, nil)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jack
4
+ module Midi
5
+ class Event
6
+ attr_reader :time, :data
7
+
8
+ def initialize(time, data)
9
+ @time = time
10
+ @data = data.is_a?(Array) ? data : data.bytes
11
+ end
12
+
13
+ def status
14
+ @data[0]
15
+ end
16
+
17
+ def channel
18
+ return nil if sysex?
19
+
20
+ status & 0x0F
21
+ end
22
+
23
+ def note_on?
24
+ (status & 0xF0) == 0x90 && velocity > 0
25
+ end
26
+
27
+ def note_off?
28
+ (status & 0xF0) == 0x80 || ((status & 0xF0) == 0x90 && velocity.zero?)
29
+ end
30
+
31
+ def control_change?
32
+ (status & 0xF0) == 0xB0
33
+ end
34
+
35
+ def program_change?
36
+ (status & 0xF0) == 0xC0
37
+ end
38
+
39
+ def pitch_bend?
40
+ (status & 0xF0) == 0xE0
41
+ end
42
+
43
+ def aftertouch?
44
+ (status & 0xF0) == 0xA0
45
+ end
46
+
47
+ def channel_pressure?
48
+ (status & 0xF0) == 0xD0
49
+ end
50
+
51
+ def sysex?
52
+ status == 0xF0
53
+ end
54
+
55
+ def note
56
+ @data[1]
57
+ end
58
+
59
+ def velocity
60
+ @data[2] || 0
61
+ end
62
+
63
+ def controller
64
+ @data[1]
65
+ end
66
+
67
+ def cc_value
68
+ @data[2]
69
+ end
70
+
71
+ def pitch_bend_value
72
+ return nil unless pitch_bend?
73
+
74
+ ((@data[2] << 7) | @data[1]) - 8192
75
+ end
76
+
77
+ def to_bytes
78
+ @data.dup
79
+ end
80
+ end
81
+ end
82
+ end