1 2 module jack.client; 3 public import jack.error; 4 public import jack.types; 5 public import jack.port; 6 import jack.midiport; 7 import jack.c.jack; 8 import jack.impl.util; 9 import std.conv: to; 10 import std.string: toStringz; 11 import core.stdc.config: c_ulong; 12 import core.stdc.errno; 13 import core.stdc.string: strcmp; 14 15 class JackClient 16 { 17 private: 18 19 jack_client_t *handle_ = null; 20 21 // callbacks 22 JackThreadDelegate *thread_callback_; 23 JackThreadInitDelegate *thread_init_callback_; 24 JackShutdownDelegate *shutdown_callback_; 25 JackInfoShutdownDelegate *info_shutdown_callback_; 26 JackProcessDelegate *process_callback_; 27 JackFreewheelDelegate *freewheel_callback_; 28 JackBufferSizeDelegate *buffer_size_callback_; 29 JackSampleRateDelegate *sample_rate_callback_; 30 JackClientRegistrationDelegate *client_registration_callback_; 31 JackPortRegistrationDelegate *port_registration_callback_; 32 JackPortConnectDelegate *port_connect_callback_; 33 JackPortRenameDelegate *port_rename_callback_; 34 JackGraphOrderDelegate *graph_order_callback_; 35 JackXRunDelegate *xrun_callback_; 36 JackLatencyDelegate *latency_callback_; 37 38 public: 39 40 static void get_version(int *major_ptr, 41 int *minor_ptr, 42 int *micro_ptr, 43 int *proto_ptr) 44 { 45 return jack_get_version(major_ptr, minor_ptr, micro_ptr, proto_ptr); 46 } 47 48 static string get_version_string() 49 { 50 return to!string(jack_get_version_string()); 51 } 52 53 @property jack_client_t *handle() 54 { 55 return handle_; 56 } 57 58 void open(string client_name, jack_options_t options, jack_status_t *status, 59 void *opt1 = null, void *opt2 = null, void *opt3 = null, void *opt4 = null) 60 { 61 handle_ = jack_client_open(client_name.toStringz, options, status, 62 opt1, opt2, opt3, opt4); 63 64 if (! handle_) { 65 throw new JackError("jack_client_open"); 66 } 67 } 68 69 void close() 70 { 71 int ret = jack_client_close(handle_); 72 if (ret != 0) { 73 throw new JackError("jack_client_close"); 74 } 75 } 76 77 string get_name() 78 { 79 return to!string(jack_get_client_name(handle_)); 80 } 81 82 void activate() 83 { 84 if (jack_activate(handle_) != 0) { 85 throw new JackError("jack_activate"); 86 } 87 } 88 89 void deactivate() 90 { 91 if (jack_deactivate(handle_) != 0) { 92 throw new JackError("jack_deactivate"); 93 } 94 } 95 96 static int get_client_pid(string name) 97 { 98 return jack_get_client_pid(name.toStringz); 99 } 100 101 jack_native_thread_t get_thread_id() 102 { 103 return jack_client_thread_id(handle_); 104 } 105 106 bool is_realtime() 107 { 108 return jack_is_realtime(handle_) != 0; 109 } 110 111 jack_nframes_t cycle_wait() 112 { 113 return jack_cycle_wait(handle_); 114 } 115 116 void cycle_signal(int status) 117 { 118 return jack_cycle_signal(handle_, status); 119 } 120 121 @property void thread_callback(JackThreadDelegate dg_) 122 { 123 auto dg = dgAllocCopy(dg_); 124 extern (C) JackThreadCallback f = function void *(void *arg) 125 { return (*cast(JackThreadDelegate *)arg)(); }; 126 int ret = jack_set_process_thread(handle_, f, dg); 127 if (ret != 0) { 128 throw new JackError("jack_set_process_thread"); 129 } 130 thread_callback_ = dg; 131 } 132 133 @property void thread_init_callback(JackThreadInitDelegate dg_) 134 { 135 auto dg = dgAllocCopy(dg_); 136 extern (C) JackThreadInitCallback f = function void(void *arg) 137 { return (*cast(JackThreadInitDelegate *)arg)(); }; 138 int ret = jack_set_thread_init_callback(handle_, f, dg); 139 if (ret != 0) { 140 throw new JackError("jack_set_thread_init_callback"); 141 } 142 thread_init_callback_ = dg; 143 } 144 145 @property 146 void on_shutdown(JackShutdownDelegate dg_) 147 { 148 auto dg = dgAllocCopy(dg_); 149 extern (C) JackShutdownCallback f = function void(void *arg) 150 { return (*cast(JackShutdownDelegate *)arg)(); }; 151 jack_on_shutdown(handle_, f, dg); 152 shutdown_callback_ = dg; 153 } 154 155 @property 156 void on_info_shutdown(JackInfoShutdownDelegate dg_) 157 { 158 auto dg = dgAllocCopy(dg_); 159 extern (C) JackInfoShutdownCallback f = function void(jack_status_t code, const(char)* reason, void *arg) 160 { return (*cast(JackInfoShutdownDelegate *)arg)(code, reason); }; 161 jack_on_info_shutdown(handle_, f, dg); 162 info_shutdown_callback_ = dg; 163 } 164 165 @property 166 void process_callback(JackProcessDelegate dg_) 167 { 168 auto dg = dgAllocCopy(dg_); 169 extern (C) JackProcessCallback f = function int(jack_nframes_t nframes, void *arg) 170 { return (*cast(JackProcessDelegate *)arg)(nframes); }; 171 int ret = jack_set_process_callback(handle_, f, dg); 172 if (ret != 0) { 173 throw new JackError("jack_set_process_callback"); 174 } 175 process_callback_ = dg; 176 } 177 178 @property 179 void freewheel_callback(JackFreewheelDelegate dg_) 180 { 181 auto dg = dgAllocCopy(dg_); 182 extern (C) JackFreewheelCallback f = function void(int starting, void *arg) 183 { return (*cast(JackFreewheelDelegate *)arg)(starting); }; 184 int ret = jack_set_freewheel_callback(handle_, f, dg); 185 if (ret != 0) { 186 throw new JackError("jack_set_freewheel_callback"); 187 } 188 freewheel_callback_ = dg; 189 } 190 191 @property 192 void buffer_size_callback(JackBufferSizeDelegate dg_) 193 { 194 auto dg = dgAllocCopy(dg_); 195 extern (C) JackBufferSizeCallback f = function int(jack_nframes_t nframes, void *arg) 196 { return (*cast(JackBufferSizeDelegate *)arg)(nframes); }; 197 int ret = jack_set_buffer_size_callback(handle_, f, dg); 198 if (ret != 0) { 199 throw new JackError("jack_set_buffer_size_callback"); 200 } 201 buffer_size_callback_ = dg; 202 } 203 204 @property 205 void sample_rate_callback(JackSampleRateDelegate dg_) 206 { 207 auto dg = dgAllocCopy(dg_); 208 extern (C) JackSampleRateCallback f = function int(jack_nframes_t nframes, void *arg) 209 { return (*cast(JackSampleRateDelegate *)arg)(nframes); }; 210 int ret = jack_set_sample_rate_callback(handle_, f, dg); 211 if (ret != 0) { 212 throw new JackError("jack_set_sample_rate_callback"); 213 } 214 sample_rate_callback_ = dg; 215 } 216 217 @property 218 void client_registration_callback(JackClientRegistrationDelegate dg_) 219 { 220 auto dg = dgAllocCopy(dg_); 221 extern (C) JackClientRegistrationCallback f = function void(const(char)* name, int register, void *arg) 222 { return (*cast(JackClientRegistrationDelegate *)arg)(name, register); }; 223 int ret = jack_set_client_registration_callback(handle_, f, dg); 224 if (ret != 0) { 225 throw new JackError("jack_set_client_registration_callback"); 226 } 227 client_registration_callback_ = dg; 228 } 229 230 @property 231 void port_registration_callback(JackPortRegistrationDelegate dg_) 232 { 233 auto dg = dgAllocCopy(dg_); 234 extern (C) JackPortRegistrationCallback f = function void(jack_port_id_t port, int register, void *arg) 235 { return (*cast(JackPortRegistrationDelegate *)arg)(port, register); }; 236 int ret = jack_set_port_registration_callback(handle_, f, dg); 237 if (ret != 0) { 238 throw new JackError("jack_set_port_registration_callback"); 239 } 240 port_registration_callback_ = dg; 241 } 242 243 @property 244 void port_connect_callback(JackPortConnectDelegate dg_) 245 { 246 auto dg = dgAllocCopy(dg_); 247 extern (C) JackPortConnectCallback f = function void(jack_port_id_t a, jack_port_id_t b, int connect, void *arg) 248 { return (*cast(JackPortConnectDelegate *)arg)(a, b, connect); }; 249 int ret = jack_set_port_connect_callback(handle_, f, dg); 250 if (ret != 0) { 251 throw new JackError("jack_set_port_connect_callback"); 252 } 253 port_connect_callback_ = dg; 254 } 255 256 @property 257 void port_rename_callback(JackPortRenameDelegate dg_) 258 { 259 auto dg = dgAllocCopy(dg_); 260 extern (C) JackPortRenameCallback f = function int(jack_port_id_t port, const(char)* old_name, const(char)* new_name, void *arg) 261 { return (*cast(JackPortRenameDelegate *)arg)(port, old_name, new_name); }; 262 int ret = jack_set_port_rename_callback(handle_, f, dg); 263 if (ret != 0) { 264 throw new JackError("jack_set_port_rename_callback"); 265 } 266 port_rename_callback_ = dg; 267 } 268 269 @property 270 void graph_order_callback(JackGraphOrderDelegate dg_) 271 { 272 auto dg = dgAllocCopy(dg_); 273 extern (C) JackGraphOrderCallback f = function int(void *arg) 274 { return (*cast(JackGraphOrderDelegate *)arg)(); }; 275 int ret = jack_set_graph_order_callback(handle_, f, dg); 276 if (ret != 0) { 277 throw new JackError("jack_set_graph_order_callback"); 278 } 279 graph_order_callback_ = dg; 280 } 281 282 @property 283 void xrun_callback(JackXRunDelegate dg_) 284 { 285 auto dg = dgAllocCopy(dg_); 286 extern (C) JackXRunCallback f = function int(void *arg) 287 { return (*cast(JackXRunDelegate *)arg)(); }; 288 int ret = jack_set_xrun_callback(handle_, f, dg); 289 if (ret != 0) { 290 throw new JackError("jack_set_xrun_callback"); 291 } 292 xrun_callback_ = dg; 293 } 294 295 @property 296 void latency_callback(JackLatencyDelegate dg_) 297 { 298 auto dg = dgAllocCopy(dg_); 299 extern (C) JackLatencyCallback f = function void(jack_latency_callback_mode_t mode, void *arg) 300 { return (*cast(JackLatencyDelegate *)arg)(mode); }; 301 int ret = jack_set_latency_callback(handle_, f, dg); 302 if (ret != 0) { 303 throw new JackError("jack_set_latency_callback"); 304 } 305 latency_callback_ = dg; 306 } 307 308 void set_freewheel(bool onoff) 309 { 310 int ret = jack_set_freewheel(handle_, onoff); 311 if (ret != 0) { 312 throw new JackError("jack_set_freewheel"); 313 } 314 } 315 316 void set_buffer_size(jack_nframes_t nframes) 317 { 318 int ret = jack_set_buffer_size(handle_, nframes); 319 if (ret != 0) { 320 throw new JackError("jack_set_buffer_size"); 321 } 322 } 323 324 jack_nframes_t get_sample_rate() 325 { 326 return jack_get_sample_rate(handle_); 327 } 328 329 jack_nframes_t get_buffer_size() 330 { 331 return jack_get_buffer_size(handle_); 332 } 333 334 float cpu_load() 335 { 336 return jack_cpu_load(handle_); 337 } 338 339 JackPort register_port(string port_name, const(char) *port_type, c_ulong flags, c_ulong buffer_size) 340 { 341 jack_port_t *c_port = jack_port_register(handle_, port_name.toStringz, port_type, flags, buffer_size); 342 if (! c_port) { 343 throw new JackError("jack_port_register"); 344 } 345 JackPort port; 346 port.handle_ = c_port; 347 return port; 348 } 349 350 void unregister_port(JackPort port) { 351 int ret = jack_port_unregister(handle_, port.handle); 352 if (ret != 0) { 353 throw new JackError("jack_port_unregister"); 354 } 355 } 356 357 bool port_is_mine(JackPort port) { 358 return jack_port_is_mine(handle_, port.handle) != 0; 359 } 360 361 string[] get_all_connections(JackPort port) 362 { 363 const(char) **c_connections = jack_port_get_all_connections(handle_, port.handle); 364 if (! c_connections) 365 return []; 366 scope(exit) jack_free(c_connections); 367 return cStringListToD(c_connections); 368 } 369 370 void request_monitor_by_name(string port_name, bool onoff) 371 { 372 if (jack_port_request_monitor_by_name(handle_, port_name.toStringz, onoff) != 0) { 373 throw new JackError("jack_port_request_monitor_by_name"); 374 } 375 } 376 377 bool connect(string source_port, string destination_port) 378 { 379 int ret = jack_connect(handle_, source_port.toStringz, destination_port.toStringz); 380 if (ret == EEXIST) { 381 return false; 382 } 383 if (ret != 0) { 384 throw new JackError("jack_connect"); 385 } 386 return true; 387 } 388 389 void disconnect(string source_port, string destination_port) 390 { 391 int ret = jack_disconnect(handle_, source_port.toStringz, destination_port.toStringz); 392 if (ret != 0) { 393 throw new JackError("jack_disconnect"); 394 } 395 } 396 397 void disconnect_port(JackPort port) 398 { 399 int ret = jack_port_disconnect(handle_, port.handle_); 400 if (ret != 0) { 401 throw new JackError("jack_port_disconnect"); 402 } 403 } 404 405 size_t get_audio_buffer_size() 406 { 407 size_t size = jack_port_type_get_buffer_size(handle_, JACK_DEFAULT_AUDIO_TYPE); 408 return size; 409 } 410 411 size_t get_midi_buffer_size() 412 { 413 size_t size = jack_port_type_get_buffer_size(handle_, JACK_DEFAULT_MIDI_TYPE); 414 return size; 415 } 416 417 void recompute_total_latencies() 418 { 419 int ret = jack_recompute_total_latencies(handle_); 420 if (ret != 0) { 421 throw new JackError("jack_recompute_total_latencies"); 422 } 423 } 424 425 string[] get_ports(string port_name_pattern, string type_name_pattern, c_ulong flags) 426 { 427 const(char) **c_ports = jack_get_ports(handle_, port_name_pattern.toStringz, type_name_pattern.toStringz, flags); 428 if (! c_ports) 429 return []; 430 scope(exit) jack_free(c_ports); 431 return cStringListToD(c_ports); 432 } 433 434 JackPort port_by_name(string port_name) 435 { 436 jack_port_t *c_port = jack_port_by_name(handle_, port_name.toStringz); 437 JackPort port; 438 port.handle_ = c_port; 439 return port; 440 } 441 442 JackPort port_by_id(jack_port_id_t port_id) 443 { 444 jack_port_t *c_port = jack_port_by_id(handle_, port_id); 445 JackPort port; 446 port.handle_ = c_port; 447 return port; 448 } 449 450 jack_nframes_t frames_since_cycle_start() 451 { 452 return jack_frames_since_cycle_start(handle_); 453 } 454 455 jack_nframes_t frame_time() 456 { 457 return jack_frame_time(handle_); 458 } 459 460 jack_nframes_t last_frame_time() 461 { 462 return jack_last_frame_time(handle_); 463 } 464 465 void get_cycle_times(jack_nframes_t *current_frames, 466 jack_time_t *current_usecs, 467 jack_time_t *next_usecs, 468 float *period_usecs) 469 { 470 int ret = jack_get_cycle_times(handle_, current_frames, current_usecs, next_usecs, period_usecs); 471 if (ret != 0) { 472 throw new JackError("jack_get_cycle_times"); 473 } 474 } 475 476 jack_time_t frames_to_time(jack_nframes_t frames) 477 { 478 return jack_frames_to_time(handle_, frames); 479 } 480 481 jack_time_t time_to_frames(jack_time_t time) 482 { 483 return jack_time_to_frames(handle_, time); 484 } 485 486 static jack_time_t get_time() 487 { 488 return jack_get_time(); 489 } 490 491 };