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 };