1 /* 2 Copyright (c) 2014 Marco Cosentino 3 4 This file is part of djack. 5 6 djack is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 djack is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with djack. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 module jack.core; 21 22 import jack.capi; 23 import std.conv; 24 import std.string; 25 26 alias jack.capi.jack_native_thread_t ThreadId; 27 alias jack.capi.JACK_POSITION_MASK JACK_POSITION_MASK; 28 29 alias jack.capi.JackOpenOptions OpenOptions; 30 alias jack.capi.JackLoadOptions LoadOptions; 31 32 alias jack_latency_range_t LatencyRange; 33 alias jack_port_id_t PortID; 34 alias jack_port_type_id_t PortTypeID; 35 36 alias jack_default_audio_sample_t DefaultAudioSample; 37 alias jack.capi.JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE; 38 39 alias jack.capi.jack_unique_t Unique; 40 alias jack.capi.jack_shmsize_t Shmsize; 41 alias jack_nframes_t NFrames; 42 alias jack_time_t Time; 43 44 alias jack.capi.JACK_MAX_FRAMES MAX_FRAMES; 45 alias jack.capi.JACK_LOAD_INIT_LIMIT LOAD_INIT_LIMIT; 46 47 alias ThreadDelegate = void* delegate(); 48 alias ThreadInitDelegate = void delegate(); 49 alias ShutdownDelegate = void delegate(); 50 alias InfoShutdownDelegate = void delegate(Status code, string reason); 51 alias ProcessDelegate = int delegate(NFrames nframes); 52 alias FreewheelDelegate = void delegate(bool starting); 53 alias BufferSizeDelegate = int delegate(NFrames nframes); 54 alias SampleRateDelegate = int delegate(NFrames nframes); 55 alias PortRegistrationDelegate = void delegate(PortID port, bool register); 56 alias PortConnectDelegate = void delegate(PortID a, PortID b, bool connect); 57 alias PortRenameDelegate = int delegate(PortID port, string oldName, string newName); 58 alias GraphOrderDelegate = int delegate(); 59 alias XRunDelegate = int delegate(); 60 alias ClientRegistrationDelegate = void delegate(string name, bool register); 61 alias LatencyDelegate = void delegate(LatencyCallbackMode mode); 62 alias SyncDelegate = int delegate(TransportState state, Position *pos); 63 alias TimebaseDelegate = void delegate(TransportState state, NFrames nframes, Position *pos, bool newPos); 64 65 alias extern(C) void function(LatencyCallbackMode mode, void* data) LatencyCallback; 66 alias extern(C) int function(NFrames nframes, void* data) ProcessCallback; 67 alias _JackThreadCallback ThreadCallback; 68 alias _JackThreadInitCallback ThreadInitCallback; 69 alias _JackGraphOrderCallback GraphOrderCallback; 70 alias _JackXRunCallback XRunCallback; 71 alias extern(C) int function(NFrames nframes, void* data) BufferSizeCallback; 72 alias extern(C) int function(NFrames nframes, void* data) SampleRateCallback; 73 alias extern(C) void function(PortID port, int register, void* data) PortRegistrationCallback; 74 alias _JackClientRegistrationCallback ClientRegistrationCallback; 75 alias extern(C) void function(PortID a, PortID b, int connect, void* data) PortConnectCallback; 76 alias extern(C) int function(PortID port, immutable(char)* old_name, immutable(char)* new_name, void* data) PortRenameCallback; 77 alias _JackFreewheelCallback FreewheelCallback; 78 alias _JackShutdownCallback ShutdownCallback; 79 alias extern(C) void function(Status code, immutable(char)* reason, void* data) InfoShutdownCallback; 80 alias extern(C) int function(TransportState state, Position *pos, void *arg) SyncCallback; 81 alias extern(C) void function(TransportState state, NFrames nframes, Position *pos, int new_pos, void *arg) TimebaseCallback; 82 83 alias jack_error_callback ErrorCallback; 84 alias jack_info_callback InfoCallback; 85 86 enum Options : jack_options_t { 87 NullOption = jack_options_t.JackNullOption, 88 NoStartServer = jack_options_t.JackNoStartServer, 89 UseExactName = jack_options_t.JackUseExactName, 90 ServerName = jack_options_t.JackServerName, 91 LoadName = jack_options_t.JackLoadName, 92 LoadInit = jack_options_t.JackLoadInit, 93 SessionID = jack_options_t.JackSessionID 94 }; 95 96 enum Status : jack_status_t { 97 Failure = jack_status_t.JackFailure, 98 InvalidOption = jack_status_t.JackInvalidOption, 99 NameNotUnique = jack_status_t.JackNameNotUnique, 100 ServerStarted = jack_status_t.JackServerStarted, 101 ServerFailed = jack_status_t.JackServerFailed, 102 ServerError = jack_status_t.JackServerError, 103 NoSuchClient = jack_status_t.JackNoSuchClient, 104 LoadFailure = jack_status_t.JackLoadFailure, 105 InitFailure = jack_status_t.JackInitFailure, 106 ShmFailure = jack_status_t.JackShmFailure, 107 VersionError = jack_status_t.JackVersionError, 108 BackendError = jack_status_t.JackBackendError, 109 ClientZombie = jack_status_t.JackClientZombie 110 }; 111 112 enum LatencyCallbackMode : jack_latency_callback_mode_t { 113 CaptureLatency = jack_latency_callback_mode_t.JackCaptureLatency, 114 PlaybackLatency = jack_latency_callback_mode_t.JackPlaybackLatency 115 } 116 117 enum PortFlags : JackPortFlags { 118 IsInput = JackPortFlags.JackPortIsInput, 119 IsOutput = JackPortFlags.JackPortIsOutput, 120 IsPhysical = JackPortFlags.JackPortIsPhysical, 121 CanMonitor = JackPortFlags.JackPortCanMonitor, 122 IsTerminal = JackPortFlags.JackPortIsTerminal 123 }; 124 125 enum TransportState : jack_transport_state_t { 126 Stopped = jack_transport_state_t.JackTransportStopped, 127 Rolling = jack_transport_state_t.JackTransportRolling, 128 Looping = jack_transport_state_t.JackTransportLooping, 129 Starting = jack_transport_state_t.JackTransportStarting, 130 NetStarting = jack_transport_state_t.JackTransportNetStarting, 131 }; 132 133 enum PositionBits : jack_position_bits_t { 134 PositionBBT = jack_position_bits_t.JackPositionBBT, 135 PositionTimecode = jack_position_bits_t.JackPositionTimecode, 136 BBTFrameOffset = jack_position_bits_t.JackBBTFrameOffset, 137 AudioVideoRatio = jack_position_bits_t.JackAudioVideoRatio, 138 VideoFrameOffset = jack_position_bits_t.JackVideoFrameOffset 139 }; 140 141 142 struct Position { 143 Unique unique_1; 144 Time usecs; 145 NFrames frame_rate; 146 NFrames frame; 147 PositionBits valid; 148 int bar; 149 int beat; 150 int tick; 151 double bar_start_tick; 152 float beats_per_bar; 153 float beat_type; 154 double ticks_per_beat; 155 double beats_per_minute; 156 double frame_time; 157 double next_time; 158 NFrames bbt_offset; 159 float audio_frames_per_video_frame; 160 NFrames video_offset; 161 int padding[7]; 162 Unique unique_2; 163 } 164 165 interface NamesArray 166 { 167 string stringAt(size_t index); 168 void dispose(); 169 string opIndex(size_t index); 170 171 @property 172 { 173 int length(); 174 bool isDisposed(); 175 } 176 } 177 178 interface Port 179 { 180 void* getBuffer(NFrames nframes); 181 bool isConnectedTo(string otherPortName); 182 NamesArray getConnections(); 183 void aliasSet(string al); 184 void aliasUnset(string al); 185 186 void requestMonitor(bool onoff); 187 void ensureMonitor(bool onoff); 188 189 LatencyRange getLatencyRange(LatencyCallbackMode callbackMode); 190 void setLatencyRange(LatencyCallbackMode callbackMode, LatencyRange lr); 191 192 @property 193 { 194 string name(); 195 void name(string newname); 196 197 string shortname(); 198 PortFlags flags(); 199 string type(); 200 PortTypeID typeID(); 201 bool connected(); 202 // TODO: It's not clear how can I interface to get the aliases 203 //string[] aliases(); 204 bool isMonitoringInput(); 205 } 206 } 207 208 209 210 interface Client 211 { 212 void close(); 213 void activate(); 214 void deactivate(); 215 216 // Port management 217 Port portRegister(string port_name, string port_type, PortFlags flags, uint buffer_size); 218 void portUnregister(Port port); 219 bool portIsMine(Port port); 220 NamesArray portGetAllConnections(Port port); 221 void portRequestMonitorByName(string name, bool onoff); 222 void portDisconnect(Port port); 223 size_t portTypeGetBufferSize(string type); 224 NamesArray getPorts(string pattern, string pattern_type, PortFlags flags); 225 Port getByName(string port_name); 226 Port getByID(PortID id); 227 void connect(string source_port, string dest_port); 228 void disconnect(string source_port, string dest_port); 229 void recomputeTotalLatencies(); 230 231 232 // Transport 233 void releaseTimebase(); 234 void transportStart(); 235 void transportStop(); 236 void setSyncTimeout(Time timeout); 237 void transportLocate(NFrames frame); 238 TransportState transportQuery(Position *pos); 239 NFrames getCurrentTransportFrame(); 240 void trasnportReposition(Position *pos); 241 242 243 // Simple Delegates interface 244 void setProcessDelegate(ProcessDelegate deleg); 245 void setShutdownDelegate(ShutdownDelegate deleg); 246 void setFreewheelDelegate(FreewheelDelegate deleg); 247 void setBufferSizeDelegate(BufferSizeDelegate deleg); 248 void setSampleRateDelegate(SampleRateDelegate deleg); 249 void setClientRegistrationDelegate(ClientRegistrationDelegate deleg); 250 void setPortRegistrationDelegate(PortRegistrationDelegate deleg); 251 void setPortConnectDelegate(PortConnectDelegate deleg); 252 void setPortRenameDelegate(PortRenameDelegate deleg); 253 void setGraphOrderDelegate(GraphOrderDelegate deleg); 254 void setXRunDelegate(XRunDelegate deleg); 255 void setLatencyDelegate(LatencyDelegate deleg); 256 void setSyncDelegate(SyncDelegate deleg); 257 void setTimebaseDelegate(bool conditional, TimebaseDelegate deleg); 258 259 // Callbacks 260 void setProcessCallback(ProcessCallback callback, void* data); 261 void setShutdownCallback(ShutdownCallback callback, void* data); 262 void setFreewheelCallback(FreewheelCallback callback, void* data); 263 void setBufferSizeCallback(BufferSizeCallback callback, void* data); 264 void setSampleRateCallback(SampleRateCallback callback, void* data); 265 void setClientRegistrationCallback(ClientRegistrationCallback callback, void* data); 266 void setPortRegistrationCallback(PortRegistrationCallback callback, void* data); 267 void setPortConnectCallback(PortConnectCallback callback, void* data); 268 void setPortRenameCallback(PortRenameCallback callback, void* data); 269 void setGraphOrderCallback(GraphOrderCallback callback, void* data); 270 void setXRunCallback(XRunCallback callback, void* data); 271 void setLatencyCallback(LatencyCallback callback, void* data); 272 void setSyncCallback(SyncCallback callback, void* data); 273 void setTimebaseCallback(bool conditional, TimebaseCallback callback, void* data); 274 275 Time framesToTime(NFrames frames); 276 NFrames timeToFrames(Time time); 277 278 @property 279 { 280 string name(); 281 ThreadId threadId(); 282 bool isRealtime(); 283 float cpuLoad(); 284 NFrames samplerate(); 285 NFrames buffersize(); 286 NFrames framesSinceCycleStart(); 287 NFrames frameTime(); 288 NFrames lastFrameTime(); 289 } 290 } 291 292 struct Version 293 { 294 int major; 295 int minor; 296 int micro; 297 int proto; 298 } 299 300 alias jack.capi.jack_ringbuffer_data_t RingbufferData; 301 302 interface RingBuffer { 303 void free(); 304 RingbufferData[] getReadVector(); 305 RingbufferData[] getWriteVector(); 306 size_t read(void* dest, size_t cnt); 307 size_t peek(void* dest, size_t cnt); 308 void readAdvance(size_t cnt); 309 void mlock(); 310 void reset(); 311 void resetSize(size_t sz); 312 size_t write(void* src, size_t cnt); 313 void writeAdvance(size_t cnt); 314 size_t getWriteSpace(); 315 size_t getReadSpace(); 316 317 @property { 318 319 ubyte *buf(); 320 size_t size(); 321 size_t sizeMask(); 322 size_t readPtr(); 323 size_t writePtr(); 324 } 325 } 326 327 // ######### Implementation ########### 328 329 import std.traits; 330 /** 331 * Creates a function which wraps the delegate call by using the data pointer 332 * which was passed when setting the callback as a ClientImplementation. 333 * It uses __traits(identifier, T) to do the call so it's mandatory to use 334 * the delegate name as stored in the ClientImplementation. 335 */ 336 private template CallbackWrapper(alias T) if(isDelegate!T) { 337 extern(C) static auto wrapper(ParameterTypeTuple!T params, void * data) { 338 auto client = cast(ClientImplementation) data; 339 return mixin("client." ~ __traits(identifier, T) ~ "(params)"); 340 } 341 } 342 343 class JackException : Exception { 344 Status status = Status.Failure; 345 346 this(string message) { 347 super(message); 348 } 349 350 this(string message, Status status) { 351 super(message); 352 this.status = status; 353 } 354 } 355 356 class NamesArrayImplementation : NamesArray { 357 immutable(char) ** rawPorts; 358 bool disposed; 359 int count; 360 361 this(immutable(char) ** rawPorts) { 362 this.rawPorts = rawPorts; 363 disposed = false; 364 count = 0; 365 while( rawPorts[count] != null ) count ++; 366 } 367 368 ~this() { 369 dispose(); 370 } 371 372 void dispose() { 373 jack_free(rawPorts); 374 disposed = true; 375 } 376 377 bool isDisposed() { 378 return disposed; 379 } 380 381 string stringAt(size_t index) { 382 if(index >= count) { 383 throw new JackException("Requested index out of bound"); 384 } 385 return to!string( rawPorts[index] ); 386 } 387 388 int length() { 389 return count; 390 } 391 392 string opIndex(size_t index) { 393 return stringAt(index); 394 } 395 } 396 397 class PortImplementation : Port { 398 jack_port_t* port; 399 400 this(jack_port_t* port) { 401 this.port = port; 402 } 403 404 string name() { 405 return to!string( jack_port_name(port) ); 406 } 407 408 void name(string newName) { 409 if( jack_port_set_name(port, toStringz(newName)) ) { 410 throw new JackException("Cannot set port name to " ~ newName); 411 } 412 } 413 414 string shortname() { 415 return to!string( jack_port_short_name(port) ); 416 } 417 418 PortFlags flags() { 419 return cast(PortFlags) jack_port_flags(port); 420 } 421 422 string type() { 423 return to!string (jack_port_type(port)); 424 } 425 426 PortTypeID typeID() { 427 return jack_port_type_id(port); 428 } 429 430 bool connected() { 431 return (jack_port_connected(port) != 0); 432 } 433 434 bool isMonitoringInput() { 435 return (jack_port_monitoring_input(port) != 0); 436 } 437 438 439 LatencyRange getLatencyRange(LatencyCallbackMode callbackMode) { 440 LatencyRange result; 441 jack_port_get_latency_range(port, callbackMode, &result); 442 return result; 443 } 444 445 void setLatencyRange(LatencyCallbackMode callbackMode, LatencyRange lr) { 446 jack_port_set_latency_range(port, callbackMode, &lr); 447 } 448 449 void* getBuffer(NFrames nframes) { 450 return jack_port_get_buffer(port, nframes); 451 } 452 453 bool isConnectedTo(string otherPortName) { 454 return (jack_port_connected_to(port, toStringz(otherPortName)) != 0); 455 } 456 457 NamesArray getConnections() { 458 immutable(char)** rawConnections = jack_port_get_connections(port); 459 if(rawConnections == null) { 460 throw new JackException("Cannot get port connections"); 461 } 462 return new NamesArrayImplementation(rawConnections); 463 } 464 465 void aliasSet(string al) { 466 if( jack_port_set_alias(port, toStringz(al)) ) { 467 throw new JackException("Cannot set port alias " ~ al); 468 } 469 } 470 471 void aliasUnset(string al) { 472 if( jack_port_unset_alias(port, toStringz(al)) ) { 473 throw new JackException("Cannot unset port alias " ~ al); 474 } 475 } 476 477 void requestMonitor(bool onoff) { 478 if( jack_port_request_monitor(port, to!int (onoff)) ){ 479 throw new JackException("Cannot request port monitor for port " ~ this.name); 480 } 481 } 482 483 void ensureMonitor(bool onoff) { 484 if( jack_port_ensure_monitor(port, to!int (onoff)) ){ 485 throw new JackException("Cannot ensure port monitor for port " ~ this.name); 486 } 487 } 488 489 @property jack_port_t* rawPointer() { 490 return port; 491 } 492 } 493 494 495 496 class ClientImplementation : Client { 497 private { 498 ThreadDelegate threadDelegate; 499 ThreadInitDelegate threadInitDelegate; 500 ShutdownDelegate shutdownDelegate; 501 InfoShutdownDelegate infoShutdownDelegate; 502 ProcessDelegate processDelegate; 503 FreewheelDelegate freewheelDelegate; 504 BufferSizeDelegate bufferSizeDelegate; 505 SampleRateDelegate sampleRateDelegate; 506 PortRegistrationDelegate portRegistrationDelegate; 507 PortConnectDelegate portConnectDelegate; 508 PortRenameDelegate portRenameDelegate; 509 GraphOrderDelegate graphOrderDelegate; 510 XRunDelegate xRunDelegate; 511 ClientRegistrationDelegate clientRegistrationDelegate; 512 LatencyDelegate latencyDelegate; 513 SyncDelegate syncDelegate; 514 TimebaseDelegate timebaseDelegate; 515 516 jack_client_t* client; 517 } 518 519 this(jack_client_t* client) { 520 this.client = client; 521 } 522 523 void close() { 524 if( jack_client_close(client) ) { 525 throw new JackException("Cannot close client"); 526 } 527 } 528 529 void activate() { 530 if(jack_activate(client)) { 531 throw new JackException("Cannot activate client"); 532 } 533 } 534 535 void deactivate() { 536 if(jack_deactivate(client)) { 537 throw new JackException("Cannot deactivate client"); 538 } 539 } 540 541 Port portRegister(string portName, string portType, PortFlags flags, uint bufferSize) { 542 jack_port_t* port = jack_port_register (client, toStringz(portName), 543 toStringz(portType), flags, bufferSize); 544 545 if( port == null ) { 546 throw new JackException("Cannot register the port"); 547 } 548 549 return new PortImplementation(port); 550 } 551 552 void portUnregister(Port port) { 553 if( jack_port_unregister(client, (cast(PortImplementation) port).rawPointer) ) { 554 throw new JackException("Cannot unregister port " ~ port.name); 555 } 556 } 557 558 bool portIsMine(Port port) { 559 return (jack_port_is_mine(client, (cast(PortImplementation) port).rawPointer) != 0); 560 } 561 562 NamesArray portGetAllConnections(Port port) { 563 immutable(char) ** rawPorts = jack_port_get_all_connections(client, 564 (cast(PortImplementation) port).rawPointer); 565 566 if(rawPorts == null) { 567 throw new JackException("Cannot get all ports connection"); 568 } 569 return new NamesArrayImplementation(rawPorts); 570 } 571 572 void portRequestMonitorByName(string name, bool onoff) { 573 if( jack_port_request_monitor_by_name(client, toStringz(name), to!int(onoff)) ) { 574 throw new JackException("Cannot request monitor by nme for " ~ name); 575 } 576 } 577 578 void portDisconnect(Port port) { 579 if( jack_port_disconnect(client, (cast(PortImplementation) port).rawPointer) ){ 580 throw new JackException("Cannot disconnect port " ~ port.name); 581 } 582 } 583 584 size_t portTypeGetBufferSize(string type) { 585 return jack_port_type_get_buffer_size(client, toStringz(type)); 586 } 587 588 NamesArray getPorts(string pattern, string patternType, PortFlags flags) { 589 immutable(char) ** rawPorts = jack_get_ports (client, toStringz(pattern), 590 toStringz(patternType), flags); 591 if(rawPorts == null) { 592 throw new JackException("Cannot get the ports"); 593 } 594 return new NamesArrayImplementation(rawPorts); 595 } 596 597 Port getByName(string portName) { 598 jack_port_t * portPtr = jack_port_by_name(client, toStringz(portName)); 599 if(portPtr == null) { 600 throw new JackException("Cannot get port " ~ portName ~ " by name"); 601 } 602 return new PortImplementation(portPtr); 603 } 604 605 Port getByID(PortID id) { 606 jack_port_t * portPtr = jack_port_by_id(client, id); 607 if(portPtr == null) { 608 throw new JackException("Cannot get port " ~ to!string(id) ~ " by ID"); 609 } 610 return new PortImplementation(portPtr); 611 } 612 613 void connect(string sourcePort, string destPort) { 614 if( jack_connect (client, toStringz(sourcePort), toStringz(destPort)) ) { 615 throw new JackException("Cannot connect the ports <" ~ sourcePort ~ "," ~ destPort ~ ">"); 616 } 617 } 618 619 void disconnect(string sourcePort, string destPort) { 620 if( jack_disconnect (client, toStringz(sourcePort), toStringz(destPort)) ) { 621 throw new JackException("Cannot disconnect the ports <" ~ sourcePort ~ "," ~ destPort ~ ">"); 622 } 623 } 624 625 void recomputeTotalLatencies() { 626 if( jack_recompute_total_latencies(client) ) { 627 throw new JackException("Cannot recompute total latencies"); 628 } 629 } 630 631 void releaseTimebase() { 632 if( jack_release_timebase(client) ) { 633 throw new JackException("Cannot release timebase"); 634 } 635 } 636 637 void transportStart() { 638 jack_transport_start(client); 639 } 640 641 void transportStop() { 642 jack_transport_stop(client); 643 } 644 645 void setSyncTimeout(Time timeout) { 646 if( jack_set_sync_timeout(client, timeout) ) { 647 throw new JackException("Cannot set sync timeout"); 648 } 649 } 650 651 void transportLocate(NFrames frame){ 652 if(jack_transport_locate(client, frame)) { 653 throw new JackException("Cannot locate frame " ~ to!string (frame)); 654 } 655 } 656 657 TransportState transportQuery(Position *pos) { 658 return cast(TransportState) jack_transport_query(client, cast(jack_position_t *) pos); 659 } 660 661 NFrames getCurrentTransportFrame() { 662 return jack_get_current_transport_frame(client); 663 } 664 665 void trasnportReposition(Position *pos) { 666 if(jack_transport_reposition(client, cast(jack_position_t *) pos)) { 667 throw new JackException("Cannot reposition"); 668 } 669 } 670 671 void setProcessDelegate(ProcessDelegate deleg) { 672 processDelegate = deleg; 673 setProcessCallback( & CallbackWrapper!(processDelegate).wrapper, cast(void *) this); 674 } 675 676 void setProcessCallback(ProcessCallback callback, void* data) { 677 if(jack_set_process_callback (client, callback, data)) { 678 throw new JackException("Cannot set process callback"); 679 } 680 } 681 682 void setShutdownDelegate(ShutdownDelegate deleg) { 683 shutdownDelegate = deleg; 684 setShutdownCallback( & CallbackWrapper!(shutdownDelegate).wrapper, cast(void *) this); 685 } 686 687 void setShutdownCallback(ShutdownCallback callback, void* data) { 688 jack_on_shutdown (client, callback, data); 689 } 690 691 void setFreewheelDelegate(FreewheelDelegate deleg) { 692 freewheelDelegate = deleg; 693 extern(C) void callback (int starting, void* data) { 694 auto client = cast(ClientImplementation) data; 695 client.freewheelDelegate(starting > 0); 696 }; 697 setFreewheelCallback(&callback , cast(void *) this); 698 } 699 700 void setFreewheelCallback(FreewheelCallback callback, void* data) { 701 if(jack_set_freewheel_callback (client, callback, data)) { 702 throw new JackException("Cannot set freewheel callback"); 703 } 704 } 705 706 void setBufferSizeDelegate(BufferSizeDelegate deleg) { 707 bufferSizeDelegate = deleg; 708 setBufferSizeCallback( & CallbackWrapper!(bufferSizeDelegate).wrapper, cast(void *) this); 709 } 710 711 void setBufferSizeCallback(BufferSizeCallback callback, void* data) { 712 if(jack_set_buffer_size_callback (client, callback, data)) { 713 throw new JackException("Cannot set buffer size callback"); 714 } 715 } 716 717 void setSampleRateDelegate(SampleRateDelegate deleg) { 718 sampleRateDelegate = deleg; 719 setSampleRateCallback(& CallbackWrapper!(sampleRateDelegate).wrapper, cast(void *) this); 720 } 721 722 void setSampleRateCallback(SampleRateCallback callback, void* data) { 723 if(jack_set_sample_rate_callback (client, callback, data)) { 724 throw new JackException("Cannot set sample rate callback"); 725 } 726 } 727 728 void setClientRegistrationDelegate(ClientRegistrationDelegate deleg) { 729 clientRegistrationDelegate = deleg; 730 extern(C) void callback(immutable(char)* name, int reg, void* data) { 731 auto client = cast(ClientImplementation) data; 732 client.clientRegistrationDelegate(to!string(name), reg > 0); 733 }; 734 setClientRegistrationCallback(&callback, cast(void *) this); 735 } 736 737 void setClientRegistrationCallback(ClientRegistrationCallback callback, void* data) { 738 if(jack_set_client_registration_callback (client, cast(_JackClientRegistrationCallback ) callback, data)) { 739 throw new JackException("Cannot set client registration callback"); 740 } 741 } 742 743 void setPortRegistrationDelegate(PortRegistrationDelegate deleg) { 744 portRegistrationDelegate = deleg; 745 extern(C) void callback(PortID port, int register, void* data) { 746 auto client = cast(ClientImplementation) data; 747 client.portRegistrationDelegate(port, register > 0); 748 } 749 setPortRegistrationCallback(&callback, cast(void *) this); 750 } 751 752 void setPortRegistrationCallback(PortRegistrationCallback callback, void* data) { 753 if(jack_set_port_registration_callback (client, callback, data)) { 754 throw new JackException("Cannot set port registration callback"); 755 } 756 } 757 758 void setPortConnectDelegate(PortConnectDelegate deleg) { 759 portConnectDelegate = deleg; 760 extern(C) void callback(PortID a, PortID b, int connect, void* data) { 761 auto client = cast(ClientImplementation) data; 762 client.portConnectDelegate(a, b, connect > 0); 763 } 764 setPortConnectCallback(&callback, cast(void *) this); 765 } 766 767 void setPortConnectCallback(PortConnectCallback callback, void* data) { 768 if(jack_set_port_connect_callback (client, cast(_JackPortConnectCallback) callback, data)) { 769 throw new JackException("Cannot set port connect callback"); 770 } 771 } 772 773 void setPortRenameDelegate(PortRenameDelegate deleg) { 774 portRenameDelegate = deleg; 775 extern(C) int callback(PortID port, immutable(char)* old_name, immutable(char)* new_name, void* data) { 776 auto client = cast(ClientImplementation) data; 777 return client.portRenameDelegate(port, to!string(old_name), to!string(new_name)); 778 } 779 setPortRenameCallback(&callback, cast(void *) this); 780 } 781 782 void setPortRenameCallback(PortRenameCallback callback, void* data) { 783 if(jack_set_port_rename_callback (client, cast(_JackPortRenameCallback) callback, data)) { 784 throw new JackException("Cannot set port rename callback"); 785 } 786 } 787 788 void setGraphOrderDelegate(GraphOrderDelegate deleg) { 789 graphOrderDelegate = deleg; 790 setGraphOrderCallback(& CallbackWrapper!(graphOrderDelegate).wrapper, cast(void *) this); 791 } 792 793 void setGraphOrderCallback(GraphOrderCallback callback, void* data) { 794 if(jack_set_graph_order_callback (client, callback, data)) { 795 throw new JackException("Cannot set graph order callback"); 796 } 797 } 798 799 void setXRunDelegate(XRunDelegate deleg) { 800 xRunDelegate = deleg; 801 setXRunCallback(& CallbackWrapper!(xRunDelegate).wrapper, cast(void *) this); 802 } 803 804 void setXRunCallback(XRunCallback callback, void* data) { 805 if(jack_set_xrun_callback (client, callback, data)) { 806 throw new JackException("Cannot set xrun callback"); 807 } 808 } 809 810 void setLatencyDelegate(LatencyDelegate deleg) { 811 latencyDelegate = deleg; 812 setLatencyCallback(& CallbackWrapper!(latencyDelegate).wrapper, cast(void *) this); 813 } 814 815 void setLatencyCallback(LatencyCallback callback, void* data) { 816 if(jack_set_latency_callback (client, cast(_JackLatencyCallback) callback, data)) { 817 throw new JackException("Cannot set latency callback"); 818 } 819 } 820 821 void setSyncDelegate(SyncDelegate deleg) { 822 syncDelegate = deleg; 823 setSyncCallback(& CallbackWrapper!(syncDelegate).wrapper, cast(void *) this); 824 } 825 826 void setSyncCallback(SyncCallback callback, void* data) { 827 if(jack_set_sync_callback(client, cast(_JackSyncCallback) callback, data)) { 828 throw new JackException("Cannot set sync callback"); 829 } 830 } 831 832 void setTimebaseDelegate(bool conditional, TimebaseDelegate deleg) { 833 timebaseDelegate = deleg; 834 extern(C) void callback(TransportState state, NFrames nframes, Position *pos, int new_pos, void *data) { 835 auto client = cast(ClientImplementation) data; 836 client.timebaseDelegate(state, nframes, pos, new_pos > 0); 837 } 838 setTimebaseCallback(conditional, &callback, cast(void *) this); 839 } 840 841 void setTimebaseCallback(bool conditional, TimebaseCallback callback, void* data) { 842 if (jack_set_timebase_callback(client, to!int(conditional), cast(_JackTimebaseCallback) callback, data)) { 843 throw new JackException("Cannot set timebase callback"); 844 } 845 } 846 847 Time framesToTime(NFrames frames) { 848 return jack_frames_to_time(client, frames); 849 } 850 851 NFrames timeToFrames(Time time) { 852 return jack_time_to_frames(client, time); 853 } 854 855 856 string name() { 857 return to!string( jack_get_client_name(client) ); 858 } 859 860 ThreadId threadId() { 861 return jack_client_thread_id(client); 862 } 863 864 bool isRealtime() { 865 return (jack_is_realtime(client) != 0); 866 } 867 868 float cpuLoad() { 869 return jack_cpu_load(client); 870 } 871 872 NFrames samplerate() { 873 return jack_get_sample_rate(client); 874 } 875 876 NFrames buffersize() { 877 return jack_get_buffer_size(client); 878 } 879 880 NFrames framesSinceCycleStart() { 881 return jack_frames_since_cycle_start(client); 882 } 883 884 NFrames frameTime() { 885 return jack_frame_time(client); 886 } 887 888 NFrames lastFrameTime() { 889 return jack_last_frame_time(client); 890 } 891 } 892 893 class RingBufferImpl : RingBuffer { 894 jack_ringbuffer_t *buffer; 895 896 this(jack_ringbuffer_t *buffer) { 897 this.buffer = buffer; 898 } 899 900 void free() { 901 jack_ringbuffer_free(buffer); 902 } 903 904 RingbufferData[] getReadVector() { 905 auto result = new RingbufferData[2]; 906 jack_ringbuffer_get_read_vector(buffer, result); 907 return result; 908 } 909 910 RingbufferData[] getWriteVector() { 911 auto result = new RingbufferData[2]; 912 jack_ringbuffer_get_write_vector(buffer, result); 913 return result; 914 } 915 916 size_t read(void* dest, size_t cnt) { 917 return jack_ringbuffer_read(buffer, dest, cnt); 918 } 919 920 size_t peek(void* dest, size_t cnt) { 921 return jack_ringbuffer_peek(buffer, dest, cnt); 922 } 923 924 void readAdvance(size_t cnt) { 925 jack_ringbuffer_read_advance(buffer, cnt); 926 } 927 928 size_t getReadSpace() { 929 return jack_ringbuffer_read_space(buffer); 930 } 931 932 void mlock() { 933 if(jack_ringbuffer_mlock(buffer) != 0) { 934 throw new JackException("Cannot lock memory"); 935 } 936 } 937 938 void reset() { 939 jack_ringbuffer_reset(buffer); 940 } 941 942 void resetSize(size_t sz) { 943 jack_ringbuffer_reset_size(buffer, sz); 944 } 945 946 size_t write(void* src, size_t cnt) { 947 return jack_ringbuffer_write(buffer, src, cnt); 948 } 949 950 void writeAdvance(size_t cnt) { 951 jack_ringbuffer_write_advance(buffer, cnt); 952 } 953 954 size_t getWriteSpace() { 955 return jack_ringbuffer_write_space(buffer); 956 } 957 958 ubyte *buf() { 959 return buffer.buf; 960 } 961 962 size_t size() { 963 return buffer.size; 964 } 965 966 size_t sizeMask() { 967 return buffer.size_mask; 968 } 969 970 size_t writePtr() { 971 return buffer.write_ptr; 972 } 973 974 size_t readPtr() { 975 return buffer.read_ptr; 976 } 977 } 978 979 // ######### Global functions 980 981 Client clientOpen(string clientName, Options options, out Status status, string serverName) { 982 jack_client_t* client; 983 984 if( status & Options.ServerName) { 985 client = jack_client_open (toStringz(clientName), options, cast(jack_status_t *) &status, toStringz(serverName)); 986 } else { 987 client = jack_client_open (toStringz(clientName), options, cast(jack_status_t *) &status); 988 } 989 990 if(client == null) { 991 throw new JackException("Cannot open client", status); 992 } 993 994 return new ClientImplementation(client); 995 } 996 997 Version getVersion() { 998 Version result; 999 jack_get_version(&result.major, &result.minor, &result.micro, &result.proto); 1000 return result; 1001 } 1002 1003 string getVersionString() { 1004 return to!string (jack_get_version_string()); 1005 } 1006 1007 int getClientPID(string name) { 1008 return jack_get_client_pid(toStringz(name)); 1009 } 1010 1011 int portNameSize() { 1012 return jack_port_name_size(); 1013 } 1014 1015 int portTypeSize() { 1016 return jack_port_type_size(); 1017 } 1018 1019 Time getTime() { 1020 return jack_get_time(); 1021 } 1022 1023 void setErrorCallback(ErrorCallback callback) { 1024 jack_set_error_function(callback); 1025 } 1026 1027 void setInfoCallback(InfoCallback callback) { 1028 jack_set_info_function(callback); 1029 } 1030 1031 RingBuffer createRingBuffer(size_t size) { 1032 jack_ringbuffer_t *buffer = jack_ringbuffer_create(size); 1033 1034 if(buffer == null) { 1035 throw new JackException("Cannot creatre ringbuffer"); 1036 } 1037 1038 return new RingBufferImpl(buffer); 1039 } 1040