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